diff --git a/build.gradle b/build.gradle index 9f3e11d0e7..f69942e2a1 100644 --- a/build.gradle +++ b/build.gradle @@ -59,7 +59,7 @@ subprojects { subproject -> ftpServerVersion = '1.0.6' - springVersionDefault = '4.0.0.BUILD-SNAPSHOT' + springVersionDefault = '4.0.0.RELEASE' springVersion = project.hasProperty('springVersion') ? getProperty('springVersion') : springVersionDefault springAmqpVersion = '1.2.0.RELEASE' @@ -296,9 +296,11 @@ project('spring-integration-http') { compile ("net.java.dev.rome:rome:1.0.0", optional) testCompile project(":spring-integration-test") - // suppress deprecation warnings (@SuppressWarnings("deprecation") is not enough for javac) - compileJava.options.compilerArgs = ["${xLintArg},-deprecation"] } + + // suppress deprecation warnings (@SuppressWarnings("deprecation") is not enough for javac) + compileJava.options.compilerArgs = ["${xLintArg},-deprecation"] + } project('spring-integration-ip') { @@ -309,6 +311,10 @@ project('spring-integration-ip') { runtime project(":spring-integration-stream") testCompile project(":spring-integration-test") } + + // suppress deprecation warnings (@SuppressWarnings("deprecation") is not enough for javac) + compileJava.options.compilerArgs = ["${xLintArg},-deprecation"] + } project('spring-integration-jdbc') { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/RouterFactoryBean.java b/spring-integration-core/src/main/java/org/springframework/integration/config/RouterFactoryBean.java index f0618b87c6..d8dc8937c6 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/RouterFactoryBean.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/RouterFactoryBean.java @@ -15,9 +15,6 @@ package org.springframework.integration.config; import java.util.Map; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - import org.springframework.expression.Expression; import org.springframework.integration.handler.AbstractReplyProducingMessageHandler; import org.springframework.integration.router.AbstractMappingMessageRouter; @@ -26,7 +23,6 @@ import org.springframework.integration.router.ExpressionEvaluatingRouter; import org.springframework.integration.router.MethodInvokingRouter; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.MessageHandler; -import org.springframework.messaging.core.DestinationResolver; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -41,8 +37,6 @@ import org.springframework.util.StringUtils; */ public class RouterFactoryBean extends AbstractStandardMessageHandlerFactoryBean { - private final Log logger = LogFactory.getLog(this.getClass()); - private volatile Map channelMappings; private volatile MessageChannel defaultOutputChannel; @@ -55,12 +49,6 @@ public class RouterFactoryBean extends AbstractStandardMessageHandlerFactoryBean private volatile Boolean ignoreSendFailures; - private volatile DestinationResolver channelResolver; - - public void setChannelResolver(DestinationResolver channelResolver) { - this.channelResolver = channelResolver; - } - public void setDefaultOutputChannel(MessageChannel defaultOutputChannel) { this.defaultOutputChannel = defaultOutputChannel; } @@ -146,10 +134,6 @@ public class RouterFactoryBean extends AbstractStandardMessageHandlerFactoryBean if (this.resolutionRequired != null) { router.setResolutionRequired(this.resolutionRequired); } - if (this.channelResolver != null) { - logger.warn("'channel-resolver' attribute has been deprecated in favor of using SpEL via 'expression' attribute"); - router.setChannelResolver(this.channelResolver); - } } @Override @@ -160,7 +144,7 @@ public class RouterFactoryBean extends AbstractStandardMessageHandlerFactoryBean private boolean noRouterAttributesProvided() { return this.channelMappings == null && this.defaultOutputChannel == null && this.timeout == null && this.resolutionRequired == null && this.applySequence == null - && this.ignoreSendFailures == null && this.channelResolver == null; + && this.ignoreSendFailures == null; } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractOutboundChannelAdapterParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractOutboundChannelAdapterParser.java index 0c10c3dd6c..be29947f09 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractOutboundChannelAdapterParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractOutboundChannelAdapterParser.java @@ -119,17 +119,6 @@ public abstract class AbstractOutboundChannelAdapterParser extends AbstractChann } } - /** - * Override this method to control the registration process and return the bean name. - * If parsing a bean definition whose name can be auto-generated, consider using - * {@link #parseConsumer(Element, ParserContext)} instead. - * @deprecated Use {@link #doParseAndRegisterConsumer(Element, ParserContext)} - */ - @Deprecated - protected String parseAndRegisterConsumer(Element element, ParserContext parserContext) { - return doParseAndRegisterConsumer(element, parserContext).getBeanName(); - } - /** * Override this method to control the registration process and return the bean name. * If parsing a bean definition whose name can be auto-generated, consider using diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractRouterParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractRouterParser.java index f105dbe78c..5d3106c6af 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractRouterParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractRouterParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 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. @@ -30,7 +30,7 @@ import org.springframework.util.xml.DomUtils; /** * Base parser for routers. - * + * * @author Mark Fisher */ public abstract class AbstractRouterParser extends AbstractConsumerEndpointParser { @@ -43,7 +43,6 @@ public abstract class AbstractRouterParser extends AbstractConsumerEndpointParse IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "resolution-required"); IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "apply-sequence"); IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "ignore-send-failures"); - IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "channel-resolver"); BeanDefinition targetRouterBeanDefinition = this.parseRouter(element, parserContext); builder.addPropertyValue("targetObject", targetRouterBeanDefinition); return builder; diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/GatewayParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/GatewayParser.java index 5a2d6bf525..3b055d5820 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/GatewayParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/GatewayParser.java @@ -27,6 +27,9 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.ManagedMap; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser; +import org.springframework.expression.common.LiteralExpression; +import org.springframework.integration.config.ExpressionFactoryBean; +import org.springframework.integration.gateway.GatewayMethodMetadata; import org.springframework.integration.gateway.GatewayProxyFactoryBean; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; @@ -105,7 +108,7 @@ public class GatewayParser extends AbstractSimpleBeanDefinitionParser { if (hasDefaultHeaders || hasDefaultPayloadExpression) { BeanDefinitionBuilder methodMetadataBuilder = BeanDefinitionBuilder.genericBeanDefinition( - "org.springframework.integration.gateway.GatewayMethodMetadata"); + GatewayMethodMetadata.class); this.setMethodInvocationHeaders(methodMetadataBuilder, invocationHeaders); IntegrationNamespaceUtils.setValueIfAttributeDefined(methodMetadataBuilder, element, "default-payload-expression", "payloadExpression"); @@ -120,7 +123,7 @@ public class GatewayParser extends AbstractSimpleBeanDefinitionParser { for (Element methodElement : elements) { String methodName = methodElement.getAttribute("name"); BeanDefinitionBuilder methodMetadataBuilder = BeanDefinitionBuilder.genericBeanDefinition( - "org.springframework.integration.gateway.GatewayMethodMetadata"); + GatewayMethodMetadata.class); methodMetadataBuilder.addPropertyValue("requestChannelName", methodElement.getAttribute("request-channel")); methodMetadataBuilder.addPropertyValue("replyChannelName", methodElement.getAttribute("reply-channel")); methodMetadataBuilder.addPropertyValue("requestTimeout", methodElement.getAttribute("request-timeout")); @@ -151,11 +154,11 @@ public class GatewayParser extends AbstractSimpleBeanDefinitionParser { } RootBeanDefinition expressionDef = null; if (hasValue) { - expressionDef = new RootBeanDefinition("org.springframework.expression.common.LiteralExpression"); + expressionDef = new RootBeanDefinition(LiteralExpression.class); expressionDef.getConstructorArgumentValues().addGenericArgumentValue(headerValue); } else if (hasExpression) { - expressionDef = new RootBeanDefinition("org.springframework.integration.config.ExpressionFactoryBean"); + expressionDef = new RootBeanDefinition(ExpressionFactoryBean.class); expressionDef.getConstructorArgumentValues().addGenericArgumentValue(headerExpression); } if (expressionDef != null) { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/PointToPointChannelParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/PointToPointChannelParser.java index 9bd4becc13..6991836820 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/PointToPointChannelParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/PointToPointChannelParser.java @@ -16,8 +16,6 @@ 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.config.TypedStringValue; @@ -43,8 +41,6 @@ import org.springframework.util.xml.DomUtils; */ public class PointToPointChannelParser extends AbstractChannelParser { - private final Log logger = LogFactory.getLog(this.getClass()); - @Override protected BeanDefinitionBuilder buildBeanDefinition(Element element, ParserContext parserContext) { BeanDefinitionBuilder builder = null; @@ -83,19 +79,10 @@ public class PointToPointChannelParser extends AbstractChannelParser { 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)) { + if (queueElement != null && dispatcherElement != null) { parserContext.getReaderContext().error( - "The 'dispatcher' attribute or sub-element " + "and any queue sub-element are mutually exclusive.", - element); + "The 'dispatcher' sub-element and any queue sub-element are mutually exclusive.", element); return null; } @@ -103,24 +90,7 @@ public class PointToPointChannelParser extends AbstractChannelParser { 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(DirectChannel.class); - if ("failover".equals(dispatcherAttribute)) { - // round-robin dispatcher is used by default, the "failover" value simply disables it - builder.addConstructorArgValue(null); - } - } - else if (dispatcherElement == null) { + if (dispatcherElement == null) { // configure the default DirectChannel with a RoundRobinLoadBalancingStrategy builder = BeanDefinitionBuilder.genericBeanDefinition(DirectChannel.class); } @@ -134,12 +104,22 @@ public class PointToPointChannelParser extends AbstractChannelParser { else { builder = BeanDefinitionBuilder.genericBeanDefinition(DirectChannel.class); } - // unless the 'load-balancer' attribute is explicitly set to 'none', + // unless the 'load-balancer' attribute is explicitly set to 'none' or 'load-balancer-ref' is explicitly configured, // configure the default RoundRobinLoadBalancingStrategy String loadBalancer = dispatcherElement.getAttribute("load-balancer"); - if ("none".equals(loadBalancer)) { - builder.addConstructorArgValue(null); + String loadBalancerRef = dispatcherElement.getAttribute("load-balancer-ref"); + if (StringUtils.hasText(loadBalancer) && StringUtils.hasText(loadBalancerRef)){ + parserContext.getReaderContext().error("'load-balancer' and 'load-balancer-ref' are mutually exclusive", element); } + if (StringUtils.hasText(loadBalancerRef)){ + builder.addConstructorArgReference(loadBalancerRef); + } + else { + if ("none".equals(loadBalancer)) { + builder.addConstructorArgValue(null); + } + } + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, dispatcherElement, "failover"); IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, dispatcherElement, "max-subscribers"); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayMethodMetadata.java b/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayMethodMetadata.java index e4a0ea49d1..71ebffcd9d 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayMethodMetadata.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayMethodMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 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. @@ -27,11 +27,12 @@ import org.springframework.expression.Expression; *

* The sub-element of a <gateway> element would look like this: * <method name="echo" request-channel="inputA" reply-timeout="2" request-timeout="200"/> - * + * * @author Oleg Zhurakousky + * @author Gary Russell * @since 2.0 */ -class GatewayMethodMetadata { +public class GatewayMethodMetadata { private volatile String payloadExpression; diff --git a/spring-integration-core/src/main/java/org/springframework/integration/json/JsonPropertyAccessor.java b/spring-integration-core/src/main/java/org/springframework/integration/json/JsonPropertyAccessor.java index 3f63e82722..0eeea55ceb 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/json/JsonPropertyAccessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/json/JsonPropertyAccessor.java @@ -41,7 +41,7 @@ public class JsonPropertyAccessor implements PropertyAccessor { /** * The kind of types this can work with. */ - private static final Class[] SUPPORTED_CLASSES = new Class[] { String.class, ToStringFriendlyJsonNode.class, + private static final Class[] SUPPORTED_CLASSES = new Class[] { String.class, ToStringFriendlyJsonNode.class, ObjectNode.class, ArrayNode.class }; // Note: ObjectMapper is thread-safe diff --git a/spring-integration-core/src/main/java/org/springframework/integration/transformer/MessageTransformingChannelInterceptor.java b/spring-integration-core/src/main/java/org/springframework/integration/transformer/MessageTransformingChannelInterceptor.java index c9db3a2b50..0fabff997e 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/transformer/MessageTransformingChannelInterceptor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/transformer/MessageTransformingChannelInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 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. @@ -24,9 +24,13 @@ import org.springframework.integration.channel.interceptor.ChannelInterceptorAda /** * A {@link ChannelInterceptor} which invokes a {@link Transformer} * when either sending-to or receiving-from a channel. - * + * + * @deprecated It is not generally recommended to perform functions + * such as transformation in a channel interceptor. + * * @author Jonas Partner */ +@Deprecated public class MessageTransformingChannelInterceptor extends ChannelInterceptorAdapter { private final Transformer transformer; diff --git a/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-3.0.xsd b/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-3.0.xsd index e4b3b8f93c..2a5e09e21d 100644 --- a/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-3.0.xsd +++ b/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-3.0.xsd @@ -286,12 +286,25 @@ (i.e. one without a queue). + + + + + + + + + A reference to a bean that implements the 'org.springframework.integration.dispatcher.LoadBalancingStrategy'. + This attribute is mutually exclusive with 'load-balancer'. + + + Defines a load-balancing strategy for the channel's dispatcher. - The default is a round-robin load - balancer. + The default is a round-robin load balancer. + This attribute is mutually exclusive with 'load-balancer-ref'. @@ -485,27 +498,6 @@ - - - - This attribute is DEPRECATED. Please use the dispatcher sub-element - instead. - - - - - - - - Enables failover, but disables load-balancing. - See the dispatcher sub-element for more - information. - - - - - - @@ -3195,20 +3187,6 @@ - - - - - - - - - - preSend(Message message, MessageChannel channel) { + return MessageBuilder.withPayload(message.getPayload().toString().toUpperCase()).build(); + } + + } + } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/channel/config/ChannelWithLoadBalancerRef-fail-config.xml b/spring-integration-core/src/test/java/org/springframework/integration/channel/config/ChannelWithLoadBalancerRef-fail-config.xml new file mode 100644 index 0000000000..b3c25540f3 --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/channel/config/ChannelWithLoadBalancerRef-fail-config.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/channel/config/DispatchingChannelParserTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/channel/config/DispatchingChannelParserTests-context.xml index 63c66021bb..f1c6b8240e 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/channel/config/DispatchingChannelParserTests-context.xml +++ b/spring-integration-core/src/test/java/org/springframework/integration/channel/config/DispatchingChannelParserTests-context.xml @@ -1,13 +1,12 @@ - - @@ -32,7 +31,13 @@ - + + + + + + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/channel/config/DispatchingChannelParserTests.java b/spring-integration-core/src/test/java/org/springframework/integration/channel/config/DispatchingChannelParserTests.java index 6e524f18f2..84b4abb430 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/channel/config/DispatchingChannelParserTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/channel/config/DispatchingChannelParserTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 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. @@ -20,28 +20,37 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import java.util.Collection; +import java.util.Iterator; import java.util.Map; +import org.hamcrest.Matchers; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.DirectFieldAccessor; -import org.springframework.beans.FatalBeanException; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; -import org.springframework.messaging.MessageChannel; import org.springframework.integration.channel.DirectChannel; import org.springframework.integration.channel.ExecutorChannel; +import org.springframework.integration.dispatcher.LoadBalancingStrategy; import org.springframework.integration.dispatcher.RoundRobinLoadBalancingStrategy; +import org.springframework.integration.test.util.TestUtils; import org.springframework.integration.util.ErrorHandlingTaskExecutor; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.MessageHandler; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * @author Mark Fisher + * @author Oleg Zhurakousky * @since 1.0.3 */ @RunWith(SpringJUnit4ClassRunner.class) @@ -54,20 +63,6 @@ public class DispatchingChannelParserTests { @Autowired private Map channels; - - @Test(expected = FatalBeanException.class) - public void dispatcherAttributeAndSubElement() { - new ClassPathXmlApplicationContext("dispatcherAttributeAndSubElement.xml", this.getClass()); - } - - @Test - public void dispatcherAttribute() { - MessageChannel channel = channels.get("dispatcherAttribute"); - assertEquals(DirectChannel.class, channel.getClass()); - assertTrue((Boolean) getDispatcherProperty("failover", channel)); - assertNull(getDispatcherProperty("loadBalancingStrategy", channel)); - } - @Test public void taskExecutorOnly() { MessageChannel channel = channels.get("taskExecutorOnly"); @@ -132,6 +127,24 @@ public class DispatchingChannelParserTests { new DirectFieldAccessor(executor).getPropertyValue("executor")); } + @Test + public void loadBalancerRef() { + MessageChannel channel = channels.get("lbRefChannel"); + LoadBalancingStrategy lbStrategy = TestUtils.getPropertyValue(channel, "dispatcher.loadBalancingStrategy", LoadBalancingStrategy.class); + assertTrue(lbStrategy instanceof SampleLoadBalancingStrategy); + } + + @Test + public void loadBalancerRefFailWithLoadBalancer() { + + try { + new ClassPathXmlApplicationContext("ChannelWithLoadBalancerRef-fail-config.xml", this.getClass()); + } + catch (BeanDefinitionParsingException e) { + assertThat(e.getMessage(), Matchers.containsString("'load-balancer' and 'load-balancer-ref' are mutually exclusive")); + } + + } private static Object getDispatcherProperty(String propertyName, MessageChannel channel) { return new DirectFieldAccessor( @@ -139,4 +152,11 @@ public class DispatchingChannelParserTests { .getPropertyValue(propertyName); } + public static class SampleLoadBalancingStrategy implements LoadBalancingStrategy { + + @Override + public Iterator getHandlerIterator(Message message, Collection handlers) { + return handlers.iterator(); + } + } } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/channel/config/channelInterceptorParserTests.xml b/spring-integration-core/src/test/java/org/springframework/integration/channel/config/channelInterceptorParserTests.xml index b2230679d5..077975d0eb 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/channel/config/channelInterceptorParserTests.xml +++ b/spring-integration-core/src/test/java/org/springframework/integration/channel/config/channelInterceptorParserTests.xml @@ -17,11 +17,7 @@ - - - - - + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/channel/config/channelParserTests.xml b/spring-integration-core/src/test/java/org/springframework/integration/channel/config/channelParserTests.xml index 70c80bd907..a752b936e1 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/channel/config/channelParserTests.xml +++ b/spring-integration-core/src/test/java/org/springframework/integration/channel/config/channelParserTests.xml @@ -11,8 +11,10 @@ - - + + + + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/channel/config/dispatcherAttributeAndSubElement.xml b/spring-integration-core/src/test/java/org/springframework/integration/channel/config/dispatcherAttributeAndSubElement.xml deleted file mode 100644 index 30c3e048b4..0000000000 --- a/spring-integration-core/src/test/java/org/springframework/integration/channel/config/dispatcherAttributeAndSubElement.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - diff --git a/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayProxyFactoryBeanTests.java b/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayProxyFactoryBeanTests.java index 342dbff7ec..5dc7ff14fc 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayProxyFactoryBeanTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayProxyFactoryBeanTests.java @@ -16,11 +16,14 @@ package org.springframework.integration.gateway; +import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; import java.lang.reflect.Method; +import java.util.Collections; import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; @@ -37,14 +40,16 @@ import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.core.convert.support.GenericConversionService; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageChannel; +import org.springframework.expression.Expression; +import org.springframework.expression.common.LiteralExpression; import org.springframework.integration.channel.DirectChannel; import org.springframework.integration.channel.QueueChannel; import org.springframework.integration.context.IntegrationContextUtils; +import org.springframework.integration.endpoint.EventDrivenConsumer; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageChannel; import org.springframework.messaging.MessageHandler; import org.springframework.messaging.PollableChannel; -import org.springframework.integration.endpoint.EventDrivenConsumer; import org.springframework.messaging.support.GenericMessage; import org.springframework.util.ReflectionUtils; @@ -77,6 +82,7 @@ public class GatewayProxyFactoryBeanTests { startResponder(requestChannel); GenericConversionService cs = new DefaultConversionService(); Converter stringToByteConverter = new Converter() { + @Override public byte[] convert(String source) { return source.getBytes(); } @@ -134,6 +140,7 @@ public class GatewayProxyFactoryBeanTests { public void testRequestReplyWithTypeConversion() throws Exception { final QueueChannel requestChannel = new QueueChannel(); new Thread(new Runnable() { + @Override public void run() { Message input = requestChannel.receive(); GenericMessage reply = new GenericMessage(input.getPayload() + "456"); @@ -184,6 +191,7 @@ public class GatewayProxyFactoryBeanTests { for (int i = 0; i < numRequests; i++) { final int count = i; executor.execute(new Runnable() { + @Override public void run() { // add some randomness to the ordering of requests try { @@ -240,6 +248,7 @@ public class GatewayProxyFactoryBeanTests { public void testMessageAsReturnValue() throws Exception { final QueueChannel requestChannel = new QueueChannel(); new Thread(new Runnable() { + @Override public void run() { Message input = requestChannel.receive(); GenericMessage reply = new GenericMessage(input.getPayload() + "bar"); @@ -291,6 +300,7 @@ public class GatewayProxyFactoryBeanTests { GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(); DirectChannel channel = new DirectChannel(); EventDrivenConsumer consumer = new EventDrivenConsumer(channel, new MessageHandler() { + @Override public void handleMessage(Message message) { Method method = ReflectionUtils.findMethod( GatewayProxyFactoryBeanTests.class, "throwTestException"); @@ -310,6 +320,7 @@ public class GatewayProxyFactoryBeanTests { private static void startResponder(final PollableChannel requestChannel) { new Thread(new Runnable() { + @Override public void run() { Message input = requestChannel.receive(); GenericMessage reply = new GenericMessage(input.getPayload() + "bar"); @@ -318,6 +329,26 @@ public class GatewayProxyFactoryBeanTests { }).start(); } + @Test + public void testProgrammaticWiring() throws Exception { + GatewayProxyFactoryBean gpfb = new GatewayProxyFactoryBean(); + gpfb.setBeanFactory(mock(BeanFactory.class)); + gpfb.setServiceInterface(TestEchoService.class); + QueueChannel drc = new QueueChannel(); + gpfb.setDefaultRequestChannel(drc); + gpfb.setDefaultReplyTimeout(0); + GatewayMethodMetadata meta = new GatewayMethodMetadata(); + meta.setHeaderExpressions(Collections. singletonMap("foo", new LiteralExpression("bar"))); + gpfb.setGlobalMethodMetadata(meta); + gpfb.afterPropertiesSet(); + ((TestEchoService) gpfb.getObject()).echo("foo"); + Message message = drc.receive(0); + assertNotNull(message); + String bar = (String) message.getHeaders().get("foo"); + assertNotNull(bar); + assertThat(bar, equalTo("bar")); + } + // @Test // public void testHistory() throws Exception { // GenericApplicationContext context = new GenericApplicationContext(); diff --git a/spring-integration-core/src/test/java/org/springframework/integration/router/config/PayloadTypeRouterParserTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/router/config/PayloadTypeRouterParserTests-context.xml index 90fe5e6449..b2235d4aa1 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/router/config/PayloadTypeRouterParserTests-context.xml +++ b/spring-integration-core/src/test/java/org/springframework/integration/router/config/PayloadTypeRouterParserTests-context.xml @@ -19,9 +19,10 @@ - + - + + @@ -32,5 +33,4 @@ service-interface="org.springframework.integration.router.config.PayloadTypeRouterParserTests$TestService" default-request-channel="routingChannel" /> - diff --git a/spring-integration-core/src/test/java/org/springframework/integration/router/config/PayloadTypeRouterParserTests.java b/spring-integration-core/src/test/java/org/springframework/integration/router/config/PayloadTypeRouterParserTests.java index d4ec5f428d..2f8eae5788 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/router/config/PayloadTypeRouterParserTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/router/config/PayloadTypeRouterParserTests.java @@ -16,9 +16,7 @@ package org.springframework.integration.router.config; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; import java.io.ByteArrayInputStream; @@ -26,16 +24,12 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.BeanDefinitionStoreException; -import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.GenericApplicationContext; import org.springframework.core.io.InputStreamResource; -import org.springframework.integration.endpoint.EventDrivenConsumer; import org.springframework.integration.support.MessageBuilder; -import org.springframework.integration.support.channel.BeanFactoryChannelResolver; -import org.springframework.integration.test.util.TestUtils; import org.springframework.messaging.Message; import org.springframework.messaging.PollableChannel; import org.springframework.test.context.ContextConfiguration; @@ -73,9 +67,6 @@ public class PayloadTypeRouterParserTests { assertTrue(chanel2.receive(100).getPayload() instanceof Integer); assertTrue(chanel3.receive(100).getPayload().getClass().isArray()); assertTrue(chanel4.receive(100).getPayload().getClass().isArray()); - - EventDrivenConsumer edc = context.getBean("routerWithChannelResolver", EventDrivenConsumer.class); - assertEquals(context.getBean("cr"), TestUtils.getPropertyValue(edc, "handler.channelResolver")); } @Test(expected=BeanDefinitionStoreException.class) @@ -119,10 +110,4 @@ public class PayloadTypeRouterParserTests { public void foo(Message message); } - public static class MyChannelResolver extends BeanFactoryChannelResolver { - - MyChannelResolver() { - super(mock(BeanFactory.class)); - } - } } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/transformer/MessageTransformingChannelInterceptorTests.java b/spring-integration-core/src/test/java/org/springframework/integration/transformer/MessageTransformingChannelInterceptorTests.java deleted file mode 100644 index df9d815711..0000000000 --- a/spring-integration-core/src/test/java/org/springframework/integration/transformer/MessageTransformingChannelInterceptorTests.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2002-2010 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.transformer; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import org.junit.Before; -import org.junit.Test; - -import org.springframework.messaging.Message; -import org.springframework.integration.channel.QueueChannel; -import org.springframework.messaging.support.GenericMessage; - -/** - * @author Jonas Partner - */ -public class MessageTransformingChannelInterceptorTests { - - private QueueChannel channel; - - private GenericMessage message; - - private TestTransformer transformer; - - private MessageTransformingChannelInterceptor channelInterceptor; - - - @Before - public void setUp() { - channel = new QueueChannel(); - message = new GenericMessage("test"); - transformer = new TestTransformer(); - channelInterceptor = new MessageTransformingChannelInterceptor(transformer); - channel.addInterceptor(channelInterceptor); - } - - - @Test - public void testTransformOnReceive() { - channelInterceptor.setTransformOnSend(false); - channel.send(message); - assertFalse("Transformer incorrectly invoked on send", transformer.invoked); - Message msg = channel.receive(1); - assertEquals("Wrong message", message, msg); - assertTrue("Transformer not invoked on receive", transformer.invoked); - } - - @Test - public void testTransformOnSend() { - channelInterceptor.setTransformOnSend(true); - channel.send(message); - assertTrue("Transformer not invoked on send", transformer.invoked); - Message msg = channel.receive(1); - assertEquals("Wrong message", message, msg); - assertEquals("Transformer invoked on receive", 1, transformer.invokedCount); - } - - - private static class TestTransformer implements Transformer { - - boolean invoked = false; - - int invokedCount = 0; - - public Message transform(Message message) { - invoked = true; - invokedCount++; - return message; - } - - } - -} diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileTailInboundChannelAdapterFactoryBean.java b/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileTailInboundChannelAdapterFactoryBean.java index 2ffa6c51a3..7cf60bdb93 100644 --- a/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileTailInboundChannelAdapterFactoryBean.java +++ b/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileTailInboundChannelAdapterFactoryBean.java @@ -110,11 +110,11 @@ public class FileTailInboundChannelAdapterFactoryBean extends AbstractFactoryBea this.outputChannel = outputChannel; } - public void setAutoStartup(Boolean autoStartup) { + public void setAutoStartup(boolean autoStartup) { this.autoStartup = autoStartup; } - public void setPhase(Integer phase) { + public void setPhase(int phase) { this.phase = phase; } diff --git a/spring-integration-http/src/main/java/org/springframework/integration/http/support/DefaultHttpHeaderMapper.java b/spring-integration-http/src/main/java/org/springframework/integration/http/support/DefaultHttpHeaderMapper.java index 99392f38ad..7fbbb73721 100644 --- a/spring-integration-http/src/main/java/org/springframework/integration/http/support/DefaultHttpHeaderMapper.java +++ b/spring-integration-http/src/main/java/org/springframework/integration/http/support/DefaultHttpHeaderMapper.java @@ -211,6 +211,7 @@ public class DefaultHttpHeaderMapper implements HeaderMapper, BeanF AGE, ALLOW, CACHE_CONTROL, + CONNECTION, CONTENT_ENCODING, CONTENT_LANGUAGE, CONTENT_LENGTH, diff --git a/spring-integration-http/src/test/java/org/springframework/integration/http/HttpProxyScenarioTests.java b/spring-integration-http/src/test/java/org/springframework/integration/http/HttpProxyScenarioTests.java index 3492357cd2..c0e0ba4533 100644 --- a/spring-integration-http/src/test/java/org/springframework/integration/http/HttpProxyScenarioTests.java +++ b/spring-integration-http/src/test/java/org/springframework/integration/http/HttpProxyScenarioTests.java @@ -50,6 +50,8 @@ import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestTemplate; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; @@ -98,6 +100,7 @@ public class HttpProxyScenarioTests { request.addHeader("If-Modified-Since", ifModifiedSinceValue); request.addHeader("If-Unmodified-Since", ifUnmodifiedSinceValue); + request.addHeader("Connection", "Keep-Alive"); Object handler = this.handlerMapping.getHandler(request).getHandler(); assertNotNull(handler); @@ -116,7 +119,11 @@ public class HttpProxyScenarioTests { HttpHeaders httpHeaders = httpEntity.getHeaders(); assertEquals(ifModifiedSince, httpHeaders.getIfNotModifiedSince()); assertEquals(ifUnmodifiedSinceValue, httpHeaders.getFirst("If-Unmodified-Since")); - return new ResponseEntity(httpEntity.getHeaders(), HttpStatus.OK); + assertEquals("Keep-Alive", httpHeaders.getFirst("Connection")); + + MultiValueMap responseHeaders = new LinkedMultiValueMap(httpHeaders); + responseHeaders.set("Connection", "close"); + return new ResponseEntity(responseHeaders, HttpStatus.OK); } }).when(template).exchange(Mockito.any(URI.class), Mockito.any(HttpMethod.class), Mockito.any(HttpEntity.class), (Class) Mockito.any(Class.class)); @@ -131,6 +138,7 @@ public class HttpProxyScenarioTests { assertNull(response.getHeaderValue("If-Modified-Since")); assertNull(response.getHeaderValue("If-Unmodified-Since")); + assertEquals("close", response.getHeaderValue("Connection")); Message message = this.checkHeadersChannel.receive(2000); MessageHeaders headers = message.getHeaders(); diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/AbstractInternetProtocolReceivingChannelAdapter.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/AbstractInternetProtocolReceivingChannelAdapter.java index 8847124d53..062fe913fa 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/AbstractInternetProtocolReceivingChannelAdapter.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/AbstractInternetProtocolReceivingChannelAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 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. @@ -17,10 +17,12 @@ package org.springframework.integration.ip; import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import org.springframework.integration.endpoint.MessageProducerSupport; +import org.springframework.util.Assert; /** * Base class for inbound TCP/UDP Channel Adapters. @@ -48,6 +50,8 @@ public abstract class AbstractInternetProtocolReceivingChannelAdapter private volatile Executor taskExecutor; + private volatile boolean taskExecutorSet; + private volatile int poolSize = 5; @@ -63,6 +67,7 @@ public abstract class AbstractInternetProtocolReceivingChannelAdapter return port; } + @Override public void setSoTimeout(int soTimeout) { this.soTimeout = soTimeout; } @@ -74,6 +79,7 @@ public abstract class AbstractInternetProtocolReceivingChannelAdapter return soTimeout; } + @Override public void setSoReceiveBufferSize(int soReceiveBufferSize) { this.soReceiveBufferSize = soReceiveBufferSize; } @@ -117,6 +123,7 @@ public abstract class AbstractInternetProtocolReceivingChannelAdapter protected void checkTaskExecutor(final String threadName) { if (this.active && this.taskExecutor == null) { Executor executor = Executors.newFixedThreadPool(this.poolSize, new ThreadFactory() { + @Override public Thread newThread(Runnable runner) { Thread thread = new Thread(runner); thread.setName(threadName); @@ -131,6 +138,10 @@ public abstract class AbstractInternetProtocolReceivingChannelAdapter @Override protected void doStop() { this.active = false; + if (!this.taskExecutorSet && this.taskExecutor != null) { + ((ExecutorService) this.taskExecutor).shutdown(); + this.taskExecutor = null; + } } public boolean isListening() { @@ -148,6 +159,7 @@ public abstract class AbstractInternetProtocolReceivingChannelAdapter return localAddress; } + @Override public void setLocalAddress(String localAddress) { this.localAddress = localAddress; } @@ -157,7 +169,9 @@ public abstract class AbstractInternetProtocolReceivingChannelAdapter } public void setTaskExecutor(Executor taskExecutor) { + Assert.notNull(taskExecutor, "'taskExecutor' cannot be null"); this.taskExecutor = taskExecutor; + this.taskExecutorSet = true; } /** diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/AbstractInternetProtocolSendingMessageHandler.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/AbstractInternetProtocolSendingMessageHandler.java index b107980e93..ca54bbfd04 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/AbstractInternetProtocolSendingMessageHandler.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/AbstractInternetProtocolSendingMessageHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 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. @@ -21,6 +21,7 @@ import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketAddress; +import org.springframework.context.Lifecycle; import org.springframework.integration.handler.AbstractMessageHandler; import org.springframework.util.Assert; @@ -30,7 +31,8 @@ import org.springframework.util.Assert; * @author Gary Russell * @since 2.0 */ -public abstract class AbstractInternetProtocolSendingMessageHandler extends AbstractMessageHandler implements CommonSocketOptions { +public abstract class AbstractInternetProtocolSendingMessageHandler extends AbstractMessageHandler implements CommonSocketOptions, + Lifecycle { private final SocketAddress destinationAddress; @@ -42,6 +44,8 @@ public abstract class AbstractInternetProtocolSendingMessageHandler extends Abst private volatile int soTimeout = -1; + private volatile boolean running; + public AbstractInternetProtocolSendingMessageHandler(String host, int port) { Assert.notNull(host, "host must not be null"); this.destinationAddress = new InetSocketAddress(host, port); @@ -55,6 +59,7 @@ public abstract class AbstractInternetProtocolSendingMessageHandler extends Abst * @see DatagramSocket#setSoTimeout(int) * @param timeout */ + @Override public void setSoTimeout(int timeout) { this.soTimeout = timeout; } @@ -64,6 +69,7 @@ public abstract class AbstractInternetProtocolSendingMessageHandler extends Abst * @see DatagramSocket#setReceiveBufferSize(int) * @param size */ + @Override public void setSoReceiveBufferSize(int size) { } @@ -72,6 +78,7 @@ public abstract class AbstractInternetProtocolSendingMessageHandler extends Abst * @see DatagramSocket#setSendBufferSize(int) * @param size */ + @Override public void setSoSendBufferSize(int size) { this.soSendBufferSize = size; } @@ -115,4 +122,31 @@ public abstract class AbstractInternetProtocolSendingMessageHandler extends Abst return soSendBufferSize; } + + @Override + public synchronized void start() { + if (!this.running) { + this.doStart(); + this.running = true; + } + } + + protected abstract void doStart(); + + @Override + public synchronized void stop() { + if (this.running) { + this.doStop(); + this.running = false; + } + } + + protected abstract void doStop(); + + @Override + public boolean isRunning() { + return this.running; + } + + } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractConnectionFactory.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractConnectionFactory.java index 36399926e9..d92ddd56c5 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractConnectionFactory.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractConnectionFactory.java @@ -410,8 +410,10 @@ public abstract class AbstractConnectionFactory extends IntegrationObjectSupport } /** - * Closes the server. + * Closes the factory. + * @deprecated As of 3.0; use {@link #stop()}. */ + @Deprecated public abstract void close(); @Override diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/CachingClientConnectionFactory.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/CachingClientConnectionFactory.java index 83f1d562e4..d1a58657db 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/CachingClientConnectionFactory.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/CachingClientConnectionFactory.java @@ -44,6 +44,7 @@ public class CachingClientConnectionFactory extends AbstractClientConnectionFact this.targetConnectionFactory = target; pool = new SimplePool(poolSize, new SimplePool.PoolItemCallback() { + @Override public TcpConnectionSupport createForPool() { try { return targetConnectionFactory.getConnection(); @@ -52,10 +53,12 @@ public class CachingClientConnectionFactory extends AbstractClientConnectionFact } } + @Override public boolean isStale(TcpConnectionSupport connection) { return !connection.isOpen(); } + @Override public void removedFromPool(TcpConnectionSupport connection) { connection.close(); } @@ -167,6 +170,7 @@ public class CachingClientConnectionFactory extends AbstractClientConnectionFact return targetConnectionFactory.isRunning(); } + @SuppressWarnings("deprecation") @Override public void close() { targetConnectionFactory.close(); @@ -317,6 +321,7 @@ public class CachingClientConnectionFactory extends AbstractClientConnectionFact public void registerListener(TcpListener listener) { super.registerListener(listener); targetConnectionFactory.registerListener(new TcpListener() { + @Override public boolean onMessage(Message message) { if (!(message instanceof ErrorMessage)) { throw new UnsupportedOperationException("This should never be called"); diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/FailoverClientConnectionFactory.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/FailoverClientConnectionFactory.java index f549ad6505..d4eb107767 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/FailoverClientConnectionFactory.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/FailoverClientConnectionFactory.java @@ -82,6 +82,7 @@ public class FailoverClientConnectionFactory extends AbstractClientConnectionFac super.registerListener(listener); for (AbstractClientConnectionFactory factory : this.factories) { factory.registerListener(new TcpListener() { + @Override public boolean onMessage(Message message) { if (!(message instanceof ErrorMessage)) { throw new UnsupportedOperationException("This should never be called"); @@ -112,6 +113,7 @@ public class FailoverClientConnectionFactory extends AbstractClientConnectionFac return failoverTcpConnection; } + @SuppressWarnings("deprecation") @Override public void close() { for (AbstractClientConnectionFactory factory : this.factories) { @@ -229,6 +231,7 @@ public class FailoverClientConnectionFactory extends AbstractClientConnectionFac this.open = false; } + @Override public boolean isOpen() { return this.open; } @@ -238,6 +241,7 @@ public class FailoverClientConnectionFactory extends AbstractClientConnectionFac * send to a new connection obtained from {@link #findAConnection()}. * If send fails on a connection from every factory, we give up. */ + @Override public synchronized void send(Message message) throws Exception { boolean success = false; AbstractClientConnectionFactory lastFactoryToTry = this.currentFactory; @@ -268,10 +272,12 @@ public class FailoverClientConnectionFactory extends AbstractClientConnectionFac } } + @Override public Object getPayload() throws Exception { return this.delegate.getPayload(); } + @Override public void run() { throw new UnsupportedOperationException("Not supported on FailoverTcpConnection"); } @@ -286,10 +292,12 @@ public class FailoverClientConnectionFactory extends AbstractClientConnectionFac return this.delegate.getHostAddress(); } + @Override public int getPort() { return this.delegate.getPort(); } + @Override public Object getDeserializerStateKey() { return this.delegate.getDeserializerStateKey(); } @@ -350,6 +358,7 @@ public class FailoverClientConnectionFactory extends AbstractClientConnectionFac * the actual connectionId in another header for convenience and tracing * purposes. */ + @Override public boolean onMessage(Message message) { if (this.delegate.getConnectionId().equals(message.getHeaders().get(IpHeaders.CONNECTION_ID))) { MessageBuilder messageBuilder = MessageBuilder.fromMessage(message) diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioClientConnectionFactory.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioClientConnectionFactory.java index 6935fbdd3b..877d4998e2 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioClientConnectionFactory.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioClientConnectionFactory.java @@ -21,6 +21,7 @@ import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.CancelledKeyException; import java.nio.channels.ClosedChannelException; +import java.nio.channels.ClosedSelectorException; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; @@ -111,10 +112,16 @@ public class TcpNioClientConnectionFactory extends this.tcpNioConnectionSupport = tcpNioSupport; } + @Deprecated @Override public void close() { if (this.selector != null) { - this.selector.wakeup(); + try { + this.selector.close(); + } + catch (IOException e) { + logger.error("Error closing selector", e); + } } } @@ -129,6 +136,7 @@ public class TcpNioClientConnectionFactory extends super.start(); } + @Override public void run() { if (logger.isDebugEnabled()) { logger.debug("Read selector running for connections to " + this.getHost() + ":" + this.getPort()); @@ -141,7 +149,8 @@ public class TcpNioClientConnectionFactory extends int selectionCount = 0; try { selectionCount = selector.select(soTimeout < 0 ? 0 : soTimeout); - } catch (CancelledKeyException cke) { + } + catch (CancelledKeyException cke) { if (logger.isDebugEnabled()) { logger.debug("CancelledKeyException during Selector.select()"); } @@ -149,7 +158,8 @@ public class TcpNioClientConnectionFactory extends while ((newChannel = newChannels.poll()) != null) { try { newChannel.register(this.selector, SelectionKey.OP_READ, channelMap.get(newChannel)); - } catch (ClosedChannelException cce) { + } + catch (ClosedChannelException cce) { if (logger.isDebugEnabled()) { logger.debug("Channel closed before registering with selector for reading"); } @@ -157,7 +167,13 @@ public class TcpNioClientConnectionFactory extends } this.processNioSelections(selectionCount, selector, null, this.channelMap); } - } catch (Exception e) { + } + catch (ClosedSelectorException cse) { + if (this.isActive()) { + logger.error("Selector closed", cse); + } + } + catch (Exception e) { logger.error("Exception in read selector thread", e); this.setActive(false); } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioServerConnectionFactory.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioServerConnectionFactory.java index 6b97ac6bb0..53f2921e33 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioServerConnectionFactory.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioServerConnectionFactory.java @@ -23,6 +23,7 @@ import java.net.Socket; import java.net.SocketException; import java.nio.channels.CancelledKeyException; import java.nio.channels.ClosedChannelException; +import java.nio.channels.ClosedSelectorException; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; @@ -67,6 +68,7 @@ public class TcpNioServerConnectionFactory extends AbstractServerConnectionFacto * connection {@link TcpConnection#run()} using the task executor. * I/O errors on the server socket/channel are logged and the factory is stopped. */ + @Override public void run() { if (this.getListener() == null) { logger.info("No listener bound to server connection factory; will not read; exiting..."); @@ -83,7 +85,8 @@ public class TcpNioServerConnectionFactory extends AbstractServerConnectionFacto if (this.getLocalAddress() == null) { this.serverChannel.socket().bind(new InetSocketAddress(port), Math.abs(this.getBacklog())); - } else { + } + else { InetAddress whichNic = InetAddress.getByName(this.getLocalAddress()); this.serverChannel.socket().bind(new InetSocketAddress(whichNic, port), Math.abs(this.getBacklog())); @@ -94,7 +97,8 @@ public class TcpNioServerConnectionFactory extends AbstractServerConnectionFacto this.selector = selector; doSelect(this.serverChannel, selector); - } catch (IOException e) { + } + catch (IOException e) { this.close(); if (this.isActive()) { logger.error("Error on ServerSocketChannel", e); @@ -127,12 +131,19 @@ public class TcpNioServerConnectionFactory extends AbstractServerConnectionFacto int selectionCount = 0; try { selectionCount = selector.select(soTimeout < 0 ? 0 : soTimeout); - } catch (CancelledKeyException cke) { + this.processNioSelections(selectionCount, selector, server, this.channelMap); + } + catch (CancelledKeyException cke) { if (logger.isDebugEnabled()) { logger.debug("CancelledKeyException during Selector.select()"); } } - this.processNioSelections(selectionCount, selector, server, this.channelMap); + catch (ClosedSelectorException cse) { + if (this.isActive()) { + logger.error("Selector closed", cse); + break; + } + } } } @@ -195,14 +206,20 @@ public class TcpNioServerConnectionFactory extends AbstractServerConnectionFacto @Override public void close() { if (this.selector != null) { - this.selector.wakeup(); + try { + this.selector.close(); + } + catch (IOException e) { + logger.error("Error closing selector", e); + } } if (this.serverChannel == null) { return; } try { this.serverChannel.close(); - } catch (IOException e) {} + } + catch (IOException e) {} this.serverChannel = null; } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/UnicastReceivingChannelAdapter.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/UnicastReceivingChannelAdapter.java index afa26a11d5..9c3749bacd 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/UnicastReceivingChannelAdapter.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/UnicastReceivingChannelAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 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. @@ -73,6 +73,7 @@ public class UnicastReceivingChannelAdapter extends AbstractInternetProtocolRece } + @Override public void run() { if (logger.isDebugEnabled()) { logger.debug("UDP Receiver running on port:" + this.getPort()); @@ -90,7 +91,7 @@ public class UnicastReceivingChannelAdapter extends AbstractInternetProtocolRece // continue } catch (SocketException e) { - doStop(); + this.stop(); } catch (Exception e) { if (e instanceof MessagingException) { @@ -133,6 +134,7 @@ public class UnicastReceivingChannelAdapter extends AbstractInternetProtocolRece protected boolean asyncSendMessage(final DatagramPacket packet) { this.getTaskExecutor().execute(new Runnable(){ + @Override public void run() { Message message = null; try { @@ -222,6 +224,7 @@ public class UnicastReceivingChannelAdapter extends AbstractInternetProtocolRece } } + @Override public void setSoSendBufferSize(int soSendBufferSize) { this.soSendBufferSize = soSendBufferSize; } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/UnicastSendingMessageHandler.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/UnicastSendingMessageHandler.java index fe657e4f44..7e9fc07a64 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/UnicastSendingMessageHandler.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/UnicastSendingMessageHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2001-2011 the original author or authors. + * Copyright 2001-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. @@ -26,6 +26,7 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; @@ -51,7 +52,7 @@ import org.springframework.util.Assert; * @since 2.0 */ public class UnicastSendingMessageHandler extends - AbstractInternetProtocolSendingMessageHandler implements Runnable{ + AbstractInternetProtocolSendingMessageHandler implements Runnable { private final DatagramPacketMessageMapper mapper = new DatagramPacketMessageMapper(); @@ -86,6 +87,8 @@ public class UnicastSendingMessageHandler extends private volatile Executor taskExecutor; + private volatile boolean taskExecutorSet; + /** * Basic constructor; no reliability; no acknowledgment. * @param host Destination host. @@ -167,12 +170,14 @@ public class UnicastSendingMessageHandler extends } } - public void onInit() { + @Override + public void doStart() { if (this.acknowledge) { if (this.taskExecutor == null) { Executor executor = Executors .newSingleThreadExecutor(new ThreadFactory() { - private AtomicInteger n = new AtomicInteger(); + private final AtomicInteger n = new AtomicInteger(); + @Override public Thread newThread(Runnable runner) { Thread thread = new Thread(runner); thread.setName("UDP-Ack-Handler-" + n.getAndIncrement()); @@ -185,10 +190,21 @@ public class UnicastSendingMessageHandler extends } } + @Override + protected void doStop() { + this.closeSocketIfNeeded(); + if (!this.taskExecutorSet && this.taskExecutor != null) { + ((ExecutorService) this.taskExecutor).shutdown(); + this.taskExecutor = null; + } + } + + @Override public void handleMessageInternal(Message message) throws MessageRejectedException, MessageHandlingException, MessageDeliveryException { if (this.acknowledge) { + Assert.state(this.isRunning(), "When 'acknowlege' is enabled, adapter must be running"); if (!this.ackThreadRunning) { synchronized(this) { if (!this.ackThreadRunning) { @@ -294,6 +310,7 @@ public class UnicastSendingMessageHandler extends /** * Process acknowledgments, if requested. */ + @Override public void run() { try { this.ackThreadRunning = true; @@ -333,7 +350,15 @@ public class UnicastSendingMessageHandler extends this.taskExecutor.execute(this); } + /** + * @deprecated Use stop() instead. + */ + @Deprecated public void shutDown() { + this.stop(); + } + + private void closeSocketIfNeeded() { if (socket != null) { socket.close(); socket = null; @@ -344,16 +369,20 @@ public class UnicastSendingMessageHandler extends * @see java.net.Socket#setReceiveBufferSize(int) * @see DatagramSocket#setReceiveBufferSize(int) */ + @Override public void setSoReceiveBufferSize(int size) { this.soReceiveBufferSize = size; } + @Override public void setLocalAddress(String localAddress) { this.localAddress = localAddress; } public void setTaskExecutor(Executor taskExecutor) { + Assert.notNull(taskExecutor, "'taskExecutor' cannot be null"); this.taskExecutor = taskExecutor; + this.taskExecutorSet = true; } /** @@ -363,6 +392,7 @@ public class UnicastSendingMessageHandler extends this.ackCounter = ackCounter; } + @Override public String getComponentType(){ return "ip:udp-outbound-channel-adapter"; } diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/config/ParserUnitTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/config/ParserUnitTests.java index fa9943ddfd..b5d1c1de49 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/config/ParserUnitTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/config/ParserUnitTests.java @@ -677,7 +677,8 @@ public class ParserUnitTests { TcpConnectionSupport connection = mock(TcpConnectionSupport.class); TcpConnectionEvent event = new TcpConnectionOpenEvent(connection, "foo"); - this.eventAdapter.setEventTypes(new Class[] {TcpConnectionEvent.class}); + Class[] types = (Class[]) new Class[]{TcpConnectionEvent.class}; + this.eventAdapter.setEventTypes(types); this.eventAdapter.onApplicationEvent(event); assertNull(this.eventChannel.receive(0)); this.eventAdapter.start(); diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/TcpOutboundGatewayTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/TcpOutboundGatewayTests.java index befacea003..16b00b182d 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/TcpOutboundGatewayTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/TcpOutboundGatewayTests.java @@ -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. @@ -85,10 +85,13 @@ public class TcpOutboundGatewayTests { AbstractConnectionFactory ccf = new TcpNetClientConnectionFactory("localhost", port); final CountDownLatch latch = new CountDownLatch(1); final AtomicBoolean done = new AtomicBoolean(); + final AtomicReference serverSocket = new AtomicReference(); Executors.newSingleThreadExecutor().execute(new Runnable() { + @Override public void run() { try { ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port, 100); + serverSocket.set(server); latch.countDown(); List sockets = new ArrayList(); int i = 0; @@ -100,7 +103,8 @@ public class TcpOutboundGatewayTests { oos.writeObject("Reply" + (i++)); sockets.add(socket); } - } catch (Exception e) { + } + catch (Exception e) { if (!done.get()) { e.printStackTrace(); } @@ -140,6 +144,8 @@ public class TcpOutboundGatewayTests { for (int i = 0; i < 100; i++) { assertTrue(replies.remove("Reply" + i)); } + done.set(true); + serverSocket.get().close(); } @Test @@ -148,6 +154,7 @@ public class TcpOutboundGatewayTests { final CountDownLatch latch = new CountDownLatch(1); final AtomicBoolean done = new AtomicBoolean(); Executors.newSingleThreadExecutor().execute(new Runnable() { + @Override public void run() { try { ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port, 10); @@ -201,6 +208,7 @@ public class TcpOutboundGatewayTests { final CountDownLatch latch = new CountDownLatch(1); final AtomicBoolean done = new AtomicBoolean(); Executors.newSingleThreadExecutor().execute(new Runnable() { + @Override public void run() { try { ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port); @@ -235,10 +243,11 @@ public class TcpOutboundGatewayTests { gateway.setRequiresReply(true); gateway.setOutputChannel(replyChannel); @SuppressWarnings("unchecked") - Future[] results = new Future[2]; + Future[] results = (Future[]) new Future[2]; for (int i = 0; i < 2; i++) { final int j = i; results[j] = (Executors.newSingleThreadExecutor().submit(new Callable(){ + @Override public Integer call() throws Exception { gateway.handleMessage(MessageBuilder.withPayload("Test" + j).build()); return 0; @@ -318,6 +327,7 @@ public class TcpOutboundGatewayTests { Executors.newSingleThreadExecutor().execute(new Runnable() { + @Override public void run() { try { ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port); @@ -363,10 +373,11 @@ public class TcpOutboundGatewayTests { gateway.setOutputChannel(replyChannel); gateway.setRemoteTimeout(500); @SuppressWarnings("unchecked") - Future[] results = new Future[2]; + Future[] results = (Future[]) new Future[2]; for (int i = 0; i < 2; i++) { final int j = i; results[j] = (Executors.newSingleThreadExecutor().submit(new Callable() { + @Override public Integer call() throws Exception { // increase the timeout after the first send if (j > 0) { @@ -418,6 +429,7 @@ public class TcpOutboundGatewayTests { Executors.newSingleThreadExecutor().execute(new Runnable() { + @Override public void run() { try { ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port); @@ -497,6 +509,7 @@ public class TcpOutboundGatewayTests { Executors.newSingleThreadExecutor().execute(new Runnable() { + @Override public void run() { try { ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port); @@ -632,14 +645,13 @@ public class TcpOutboundGatewayTests { Executors.newSingleThreadExecutor().execute(new Runnable() { + @Override public void run() { try { ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port); latch.countDown(); - int i = 0; while (!done.get()) { Socket socket = server.accept(); - i++; while (!socket.isClosed()) { try { ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/ConnectionFactoryShutDownTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/ConnectionFactoryShutDownTests.java index b3b9ea5ef8..636fc28afc 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/ConnectionFactoryShutDownTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/ConnectionFactoryShutDownTests.java @@ -22,6 +22,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import org.junit.Test; + import org.springframework.messaging.MessagingException; import org.springframework.util.StopWatch; @@ -36,13 +37,16 @@ public class ConnectionFactoryShutDownTests { public void testShutdownDoesntDeadlock() throws Exception { final AbstractConnectionFactory factory = new AbstractConnectionFactory(0) { + @Override public TcpConnection getConnection() throws Exception { return null; } @Override + @Deprecated public void close() { } + }; factory.setActive(true); Executor executor = factory.getTaskExecutor(); @@ -50,6 +54,7 @@ public class ConnectionFactoryShutDownTests { final CountDownLatch latch2 = new CountDownLatch(1); executor.execute(new Runnable() { + @Override public void run() { latch1.countDown(); try { diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpConnectionEventListenerTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpConnectionEventListenerTests.java index 434903c240..46fee7eba2 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpConnectionEventListenerTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpConnectionEventListenerTests.java @@ -65,7 +65,8 @@ public class TcpConnectionEventListenerTests { TcpConnectionEventListeningMessageProducer eventProducer = new TcpConnectionEventListeningMessageProducer(); QueueChannel outputChannel = new QueueChannel(); eventProducer.setOutputChannel(outputChannel); - eventProducer.setEventTypes(new Class[] {FooEvent.class, BarEvent.class}); + Class[] eventTypes = new Class[]{FooEvent.class, BarEvent.class}; + eventProducer.setEventTypes((Class[]) eventTypes); eventProducer.afterPropertiesSet(); eventProducer.start(); TcpConnectionSupport connection = Mockito.mock(TcpConnectionSupport.class); diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpNioConnectionReadTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpNioConnectionReadTests.java index 682e55c0ea..848e180b0b 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpNioConnectionReadTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpNioConnectionReadTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 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. @@ -20,9 +20,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import java.io.IOException; import java.net.Socket; -import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; @@ -32,7 +30,7 @@ import java.util.concurrent.TimeUnit; import javax.net.SocketFactory; import org.junit.Test; -import org.springframework.messaging.Message; + import org.springframework.integration.ip.tcp.serializer.AbstractByteArraySerializer; import org.springframework.integration.ip.tcp.serializer.ByteArrayCrLfSerializer; import org.springframework.integration.ip.tcp.serializer.ByteArrayLengthHeaderSerializer; @@ -40,6 +38,7 @@ import org.springframework.integration.ip.tcp.serializer.ByteArrayStxEtxSerializ import org.springframework.integration.ip.util.SocketTestUtils; import org.springframework.integration.ip.util.TestingUtilities; import org.springframework.integration.test.util.SocketUtils; +import org.springframework.messaging.Message; /** * @author Gary Russell @@ -47,7 +46,7 @@ import org.springframework.integration.test.util.SocketUtils; */ public class TcpNioConnectionReadTests { - private CountDownLatch latch = new CountDownLatch(1); + private final CountDownLatch latch = new CountDownLatch(1); private AbstractServerConnectionFactory getConnectionFactory(int port, AbstractByteArraySerializer serializer, TcpListener listener) throws Exception { @@ -68,10 +67,6 @@ public class TcpNioConnectionReadTests { return scf; } - /** - * Test method for {@link org.springframework.integration.ip.tcp.NioSocketReader}. - */ - @SuppressWarnings("unchecked") @Test public void testReadLength() throws Exception { int port = SocketUtils.findAvailableServerSocket(); @@ -79,6 +74,7 @@ public class TcpNioConnectionReadTests { final List> responses = new ArrayList>(); final Semaphore semaphore = new Semaphore(0); AbstractServerConnectionFactory scf = getConnectionFactory(port, serializer,new TcpListener() { + @Override public boolean onMessage(Message message) { responses.add(message); semaphore.release(); @@ -88,16 +84,17 @@ public class TcpNioConnectionReadTests { // Fire up the sender. - SocketTestUtils.testSendLength(port, latch); + CountDownLatch done = SocketTestUtils.testSendLength(port, latch); latch.countDown(); assertTrue(semaphore.tryAcquire(1, 10000, TimeUnit.MILLISECONDS)); assertTrue(semaphore.tryAcquire(1, 10000, TimeUnit.MILLISECONDS)); assertEquals("Did not receive data", 2, responses.size()); assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING, - new String(((Message) responses.get(0)).getPayload())); + new String((byte[]) responses.get(0).getPayload())); assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING, - new String(((Message) responses.get(1)).getPayload())); - scf.close(); + new String((byte[]) responses.get(1).getPayload())); + scf.stop(); + done.countDown(); } @@ -110,11 +107,15 @@ public class TcpNioConnectionReadTests { final List> responses = new ArrayList>(); final Semaphore semaphore = new Semaphore(0); AbstractServerConnectionFactory scf = getConnectionFactory(port, serializer,new TcpListener() { + @Override public boolean onMessage(Message message) { responses.add(message); try { Thread.sleep(1000); - } catch (InterruptedException e) { } + } + catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } semaphore.release(); return false; } @@ -123,19 +124,17 @@ public class TcpNioConnectionReadTests { int howMany = 2; scf.setBacklog(howMany + 5); // Fire up the sender. - SocketTestUtils.testSendFragmented(port, howMany, false); + CountDownLatch done = SocketTestUtils.testSendFragmented(port, howMany, false); assertTrue(semaphore.tryAcquire(howMany, 20000, TimeUnit.MILLISECONDS)); assertEquals("Expected", howMany, responses.size()); for (int i = 0; i < howMany; i++) { assertEquals("Data", "xx", new String(((Message) responses.get(0)).getPayload())); } - scf.close(); + scf.stop(); + done.countDown(); } - /** - * Test method for {@link org.springframework.integration.ip.tcp.NioSocketReader}. - */ @SuppressWarnings("unchecked") @Test public void testReadStxEtx() throws Exception { @@ -144,6 +143,7 @@ public class TcpNioConnectionReadTests { final List> responses = new ArrayList>(); final Semaphore semaphore = new Semaphore(0); AbstractServerConnectionFactory scf = getConnectionFactory(port, serializer,new TcpListener() { + @Override public boolean onMessage(Message message) { responses.add(message); semaphore.release(); @@ -153,7 +153,7 @@ public class TcpNioConnectionReadTests { // Fire up the sender. - SocketTestUtils.testSendStxEtx(port, latch); + CountDownLatch done = SocketTestUtils.testSendStxEtx(port, latch); latch.countDown(); assertTrue(semaphore.tryAcquire(1, 10000, TimeUnit.MILLISECONDS)); assertTrue(semaphore.tryAcquire(1, 10000, TimeUnit.MILLISECONDS)); @@ -162,7 +162,8 @@ public class TcpNioConnectionReadTests { new String(((Message) responses.get(0)).getPayload())); assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING, new String(((Message) responses.get(1)).getPayload())); - scf.close(); + scf.stop(); + done.countDown(); } /** @@ -176,6 +177,7 @@ public class TcpNioConnectionReadTests { final List> responses = new ArrayList>(); final Semaphore semaphore = new Semaphore(0); AbstractServerConnectionFactory scf = getConnectionFactory(port, serializer,new TcpListener() { + @Override public boolean onMessage(Message message) { responses.add(message); semaphore.release(); @@ -185,7 +187,7 @@ public class TcpNioConnectionReadTests { // Fire up the sender. - SocketTestUtils.testSendCrLf(port, latch); + CountDownLatch done = SocketTestUtils.testSendCrLf(port, latch); latch.countDown(); assertTrue(semaphore.tryAcquire(1, 10000, TimeUnit.MILLISECONDS)); assertTrue(semaphore.tryAcquire(1, 10000, TimeUnit.MILLISECONDS)); @@ -194,31 +196,30 @@ public class TcpNioConnectionReadTests { new String(((Message) responses.get(0)).getPayload())); assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING, new String(((Message) responses.get(1)).getPayload())); - scf.close(); + scf.stop(); + done.countDown(); } - /** - * Test method for {@link org.springframework.integration.ip.tcp.NioSocketReader}. - */ @Test public void testReadLengthOverflow() throws Exception { int port = SocketUtils.findAvailableServerSocket(); ByteArrayLengthHeaderSerializer serializer = new ByteArrayLengthHeaderSerializer(); - final List> responses = new ArrayList>(); final Semaphore semaphore = new Semaphore(0); final List added = new ArrayList(); final List removed = new ArrayList(); AbstractServerConnectionFactory scf = getConnectionFactory(port, serializer,new TcpListener() { + @Override public boolean onMessage(Message message) { - responses.add(message); semaphore.release(); return false; } }, new TcpSender() { + @Override public void addNewConnection(TcpConnection connection) { added.add(connection); semaphore.release(); } + @Override public void removeDeadConnection(TcpConnection connection) { removed.add(connection); semaphore.release(); @@ -227,37 +228,36 @@ public class TcpNioConnectionReadTests { // Fire up the sender. - SocketTestUtils.testSendLengthOverflow(port); + CountDownLatch done = SocketTestUtils.testSendLengthOverflow(port); whileOpen(semaphore, added); assertEquals(1, added.size()); assertTrue(semaphore.tryAcquire(10000, TimeUnit.MILLISECONDS)); assertTrue(removed.size() > 0); - scf.close(); + scf.stop(); + done.countDown(); } - /** - * Test method for {@link org.springframework.integration.ip.tcp.NioSocketReader}. - */ @Test public void testReadStxEtxOverflow() throws Exception { int port = SocketUtils.findAvailableServerSocket(); ByteArrayStxEtxSerializer serializer = new ByteArrayStxEtxSerializer(); serializer.setMaxMessageSize(1024); - final List> responses = new ArrayList>(); final Semaphore semaphore = new Semaphore(0); final List added = new ArrayList(); final List removed = new ArrayList(); AbstractServerConnectionFactory scf = getConnectionFactory(port, serializer,new TcpListener() { + @Override public boolean onMessage(Message message) { - responses.add(message); semaphore.release(); return false; } }, new TcpSender() { + @Override public void addNewConnection(TcpConnection connection) { added.add(connection); semaphore.release(); } + @Override public void removeDeadConnection(TcpConnection connection) { removed.add(connection); semaphore.release(); @@ -266,37 +266,36 @@ public class TcpNioConnectionReadTests { // Fire up the sender. - SocketTestUtils.testSendStxEtxOverflow(port); + CountDownLatch done = SocketTestUtils.testSendStxEtxOverflow(port); whileOpen(semaphore, added); assertEquals(1, added.size()); assertTrue(semaphore.tryAcquire(10000, TimeUnit.MILLISECONDS)); assertTrue(removed.size() > 0); - scf.close(); + scf.stop(); + done.countDown(); } - /** - * Test method for {@link org.springframework.integration.ip.tcp.NioSocketReader}. - */ @Test public void testReadCrLfOverflow() throws Exception { int port = SocketUtils.findAvailableServerSocket(); ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer(); serializer.setMaxMessageSize(1024); - final List> responses = new ArrayList>(); final Semaphore semaphore = new Semaphore(0); final List added = new ArrayList(); final List removed = new ArrayList(); AbstractServerConnectionFactory scf = getConnectionFactory(port, serializer,new TcpListener() { + @Override public boolean onMessage(Message message) { - responses.add(message); semaphore.release(); return false; } }, new TcpSender() { + @Override public void addNewConnection(TcpConnection connection) { added.add(connection); semaphore.release(); } + @Override public void removeDeadConnection(TcpConnection connection) { removed.add(connection); semaphore.release(); @@ -305,12 +304,13 @@ public class TcpNioConnectionReadTests { // Fire up the sender. - SocketTestUtils.testSendCrLfOverflow(port); + CountDownLatch done = SocketTestUtils.testSendCrLfOverflow(port); whileOpen(semaphore, added); assertEquals(1, added.size()); assertTrue(semaphore.tryAcquire(10000, TimeUnit.MILLISECONDS)); assertTrue(removed.size() > 0); - scf.close(); + scf.stop(); + done.countDown(); } /** @@ -323,21 +323,22 @@ public class TcpNioConnectionReadTests { int port = SocketUtils.findAvailableServerSocket(); ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer(); serializer.setMaxMessageSize(1024); - final List> responses = new ArrayList>(); final Semaphore semaphore = new Semaphore(0); final List added = new ArrayList(); final List removed = new ArrayList(); AbstractServerConnectionFactory scf = getConnectionFactory(port, serializer,new TcpListener() { + @Override public boolean onMessage(Message message) { - responses.add(message); semaphore.release(); return false; } }, new TcpSender() { + @Override public void addNewConnection(TcpConnection connection) { added.add(connection); semaphore.release(); } + @Override public void removeDeadConnection(TcpConnection connection) { removed.add(connection); semaphore.release(); @@ -349,7 +350,7 @@ public class TcpNioConnectionReadTests { assertEquals(1, added.size()); assertTrue(semaphore.tryAcquire(10000, TimeUnit.MILLISECONDS)); assertTrue(removed.size() > 0); - scf.close(); + scf.stop(); } /** @@ -362,21 +363,22 @@ public class TcpNioConnectionReadTests { int port = SocketUtils.findAvailableServerSocket(); ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer(); serializer.setMaxMessageSize(1024); - final List> responses = new ArrayList>(); final Semaphore semaphore = new Semaphore(0); final List added = new ArrayList(); final List removed = new ArrayList(); AbstractServerConnectionFactory scf = getConnectionFactory(port, serializer,new TcpListener() { + @Override public boolean onMessage(Message message) { - responses.add(message); semaphore.release(); return false; } }, new TcpSender() { + @Override public void addNewConnection(TcpConnection connection) { added.add(connection); semaphore.release(); } + @Override public void removeDeadConnection(TcpConnection connection) { removed.add(connection); semaphore.release(); @@ -389,7 +391,7 @@ public class TcpNioConnectionReadTests { assertEquals(1, added.size()); assertTrue(semaphore.tryAcquire(10000, TimeUnit.MILLISECONDS)); assertTrue(removed.size() > 0); - scf.close(); + scf.stop(); } /** @@ -428,23 +430,25 @@ public class TcpNioConnectionReadTests { } private void testClosureMidMessageGuts(AbstractByteArraySerializer serializer, String shortMessage) - throws Exception, IOException, UnknownHostException, - InterruptedException { + throws Exception { final int port = SocketUtils.findAvailableServerSocket(); final List> responses = new ArrayList>(); final Semaphore semaphore = new Semaphore(0); final List added = new ArrayList(); final List removed = new ArrayList(); AbstractServerConnectionFactory scf = getConnectionFactory(port, serializer,new TcpListener() { + @Override public boolean onMessage(Message message) { responses.add(message); return false; } }, new TcpSender() { + @Override public void addNewConnection(TcpConnection connection) { added.add(connection); semaphore.release(); } + @Override public void removeDeadConnection(TcpConnection connection) { removed.add(connection); semaphore.release(); @@ -457,7 +461,7 @@ public class TcpNioConnectionReadTests { assertEquals(1, added.size()); assertTrue(semaphore.tryAcquire(10000, TimeUnit.MILLISECONDS)); assertTrue(removed.size() > 0); - scf.close(); + scf.stop(); } private void whileOpen(Semaphore semaphore, final List added) diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpNioConnectionTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpNioConnectionTests.java index 564fd7ddcc..c8345daa27 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpNioConnectionTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpNioConnectionTests.java @@ -50,6 +50,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; + import javax.net.ServerSocketFactory; import org.junit.Test; @@ -81,6 +82,7 @@ import org.springframework.util.ReflectionUtils.FieldFilter; public class TcpNioConnectionTests { private final ApplicationEventPublisher nullPublisher = new ApplicationEventPublisher() { + @Override public void publishEvent(ApplicationEvent event) { } }; @@ -92,16 +94,21 @@ public class TcpNioConnectionTests { factory.setSoTimeout(1000); factory.start(); final CountDownLatch latch = new CountDownLatch(1); + final CountDownLatch done = new CountDownLatch(1); + final AtomicReference serverSocket = new AtomicReference(); Executors.newSingleThreadExecutor().execute(new Runnable() { + @Override @SuppressWarnings("unused") public void run() { try { ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port); + serverSocket.set(server); latch.countDown(); Socket s = server.accept(); // block so we fill the buffer - server.accept(); - } catch (Exception e) { + done.await(10, TimeUnit.SECONDS); + } + catch (Exception e) { e.printStackTrace(); } } @@ -110,10 +117,13 @@ public class TcpNioConnectionTests { try { TcpConnection connection = factory.getConnection(); connection.send(MessageBuilder.withPayload(new byte[1000000]).build()); - } catch (Exception e) { + } + catch (Exception e) { assertTrue("Expected SocketTimeoutException, got " + e.getClass().getSimpleName() + ":" + e.getMessage(), e instanceof SocketTimeoutException); } + done.countDown(); + serverSocket.get().close(); } @Test @@ -123,17 +133,22 @@ public class TcpNioConnectionTests { factory.setSoTimeout(1000); factory.start(); final CountDownLatch latch = new CountDownLatch(1); + final CountDownLatch done = new CountDownLatch(1); + final AtomicReference serverSocket = new AtomicReference(); Executors.newSingleThreadExecutor().execute(new Runnable() { + @Override public void run() { try { ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port); + serverSocket.set(server); latch.countDown(); Socket socket = server.accept(); byte[] b = new byte[6]; readFully(socket.getInputStream(), b); // block to cause timeout on read. - server.accept(); - } catch (Exception e) { + done.await(10, TimeUnit.SECONDS); + } + catch (Exception e) { e.printStackTrace(); } } @@ -150,9 +165,12 @@ public class TcpNioConnectionTests { } } assertTrue(!connection.isOpen()); - } catch (Exception e) { + } + catch (Exception e) { fail("Unexpected exception " + e); } + done.countDown(); + serverSocket.get().close(); } @Test @@ -162,15 +180,19 @@ public class TcpNioConnectionTests { factory.setNioHarvestInterval(100); factory.start(); final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference serverSocket = new AtomicReference(); Executors.newSingleThreadExecutor().execute(new Runnable() { + @Override public void run() { try { ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port); + serverSocket.set(server); latch.countDown(); Socket socket = server.accept(); byte[] b = new byte[6]; readFully(socket.getInputStream(), b); - } catch (Exception e) { + } + catch (Exception e) { e.printStackTrace(); } } @@ -182,8 +204,7 @@ public class TcpNioConnectionTests { assertEquals(1, connections.size()); connection.close(); assertTrue(!connection.isOpen()); - // force a wakeup of the selector - factory.close(); + TestUtils.getPropertyValue(factory, "selector", Selector.class).wakeup(); int n = 0; while (connections.size() > 0) { Thread.sleep(100); @@ -192,11 +213,13 @@ public class TcpNioConnectionTests { } } assertEquals(0, connections.size()); - } catch (Exception e) { + } + catch (Exception e) { e.printStackTrace(); fail("Unexpected exception " + e); } factory.stop(); + serverSocket.get().close(); } @Test @@ -216,6 +239,7 @@ public class TcpNioConnectionTests { final List fields = new ArrayList(); ReflectionUtils.doWithFields(SocketChannel.class, new FieldCallback() { + @Override public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { field.setAccessible(true); @@ -223,6 +247,7 @@ public class TcpNioConnectionTests { } }, new FieldFilter() { + @Override public boolean matches(Field field) { return field.getName().equals("open"); }}); @@ -265,11 +290,13 @@ public class TcpNioConnectionTests { public void testInsufficientThreads() throws Exception { final ExecutorService exec = Executors.newFixedThreadPool(2); Future future = exec.submit(new Callable() { + @Override public Object call() throws Exception { SocketChannel channel = mock(SocketChannel.class); Socket socket = mock(Socket.class); Mockito.when(channel.socket()).thenReturn(socket); doAnswer(new Answer() { + @Override public Integer answer(InvocationOnMock invocation) throws Throwable { ByteBuffer buffer = (ByteBuffer) invocation.getArguments()[0]; buffer.position(1); @@ -311,11 +338,13 @@ public class TcpNioConnectionTests { final ExecutorService exec = Executors.newFixedThreadPool(3); final CountDownLatch messageLatch = new CountDownLatch(1); Future future = exec.submit(new Callable() { + @Override public Object call() throws Exception { SocketChannel channel = mock(SocketChannel.class); Socket socket = mock(Socket.class); Mockito.when(channel.socket()).thenReturn(socket); doAnswer(new Answer() { + @Override public Integer answer(InvocationOnMock invocation) throws Throwable { ByteBuffer buffer = (ByteBuffer) invocation.getArguments()[0]; buffer.position(1025); @@ -327,6 +356,7 @@ public class TcpNioConnectionTests { final TcpNioConnection connection = new TcpNioConnection(channel, false, false, null, null); connection.setTaskExecutor(exec); connection.registerListener(new TcpListener(){ + @Override public boolean onMessage(Message message) { messageLatch.countDown(); return false; @@ -438,6 +468,7 @@ public class TcpNioConnectionTests { final byte[] out = new byte[4]; ExecutorService exec = Executors.newSingleThreadExecutor(); exec.execute(new Runnable(){ + @Override public void run() { try { stream.read(out); @@ -468,6 +499,7 @@ public class TcpNioConnectionTests { inboundConnection.setMapper(inMapper); final ByteArrayOutputStream written = new ByteArrayOutputStream(); doAnswer(new Answer() { + @Override public Integer answer(InvocationOnMock invocation) throws Throwable { ByteBuffer buff = (ByteBuffer) invocation.getArguments()[0]; byte[] bytes = written.toByteArray(); @@ -481,6 +513,7 @@ public class TcpNioConnectionTests { when(outChannel.socket()).thenReturn(outSocket); TcpNioConnection outboundConnection = new TcpNioConnection(outChannel, true, false, nullPublisher, null); doAnswer(new Answer() { + @Override public Object answer(InvocationOnMock invocation) throws Throwable { ByteBuffer buff = (ByteBuffer) invocation.getArguments()[0]; byte[] bytes = new byte[buff.limit()]; @@ -505,6 +538,7 @@ public class TcpNioConnectionTests { final CountDownLatch latch = new CountDownLatch(1); TcpListener listener = new TcpListener() { + @Override public boolean onMessage(Message message) { inboundMessage.set(message); latch.countDown(); diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpNioConnectionWriteTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpNioConnectionWriteTests.java index 5aaaf763db..90cdcf63a2 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpNioConnectionWriteTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpNioConnectionWriteTests.java @@ -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. @@ -23,10 +23,13 @@ import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; import java.nio.ByteBuffer; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import javax.net.ServerSocketFactory; import org.junit.Test; + import org.springframework.integration.ip.tcp.serializer.AbstractByteArraySerializer; import org.springframework.integration.ip.tcp.serializer.ByteArrayCrLfSerializer; import org.springframework.integration.ip.tcp.serializer.ByteArrayLengthHeaderSerializer; @@ -58,15 +61,18 @@ public class TcpNioConnectionWriteTests { ServerSocket server = ServerSocketFactory.getDefault() .createServerSocket(port); server.setSoTimeout(10000); + final CountDownLatch latch = new CountDownLatch(1); Thread t = new Thread(new Runnable() { + @Override public void run() { try { ByteArrayLengthHeaderSerializer serializer = new ByteArrayLengthHeaderSerializer(); AbstractConnectionFactory ccf = getClientConnectionFactory(false, port, serializer); TcpConnection connection = ccf.getConnection(); connection.send(MessageBuilder.withPayload(testString.getBytes()).build()); - Thread.sleep(1000000000L); - } catch (Exception e) { + latch.await(10, TimeUnit.SECONDS); + } + catch (Exception e) { e.printStackTrace(); } } @@ -82,6 +88,7 @@ public class TcpNioConnectionWriteTests { assertEquals(testString.length(), buffer.getInt()); assertEquals(testString, new String(buff, 4, testString.length())); server.close(); + latch.countDown(); } @Test @@ -91,15 +98,18 @@ public class TcpNioConnectionWriteTests { ServerSocket server = ServerSocketFactory.getDefault() .createServerSocket(port); server.setSoTimeout(10000); + final CountDownLatch latch = new CountDownLatch(1); Thread t = new Thread(new Runnable() { + @Override public void run() { try { ByteArrayStxEtxSerializer serializer = new ByteArrayStxEtxSerializer(); AbstractConnectionFactory ccf = getClientConnectionFactory(false, port, serializer); TcpConnection connection = ccf.getConnection(); connection.send(MessageBuilder.withPayload(testString.getBytes()).build()); - Thread.sleep(1000000000L); - } catch (Exception e) { + latch.await(10, TimeUnit.SECONDS); + } + catch (Exception e) { e.printStackTrace(); } } @@ -115,6 +125,7 @@ public class TcpNioConnectionWriteTests { assertEquals(testString, new String(buff, 1, testString.length())); assertEquals(ByteArrayStxEtxSerializer.ETX, buff[testString.length() + 1]); server.close(); + latch.countDown(); } @Test @@ -124,15 +135,18 @@ public class TcpNioConnectionWriteTests { ServerSocket server = ServerSocketFactory.getDefault() .createServerSocket(port); server.setSoTimeout(10000); + final CountDownLatch latch = new CountDownLatch(1); Thread t = new Thread(new Runnable() { + @Override public void run() { try { ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer(); AbstractConnectionFactory ccf = getClientConnectionFactory(false, port, serializer); TcpConnection connection = ccf.getConnection(); connection.send(MessageBuilder.withPayload(testString.getBytes()).build()); - Thread.sleep(1000000000L); - } catch (Exception e) { + latch.await(10, TimeUnit.SECONDS); + } + catch (Exception e) { e.printStackTrace(); } } @@ -148,6 +162,7 @@ public class TcpNioConnectionWriteTests { assertEquals('\r', buff[testString.length()]); assertEquals('\n', buff[testString.length() + 1]); server.close(); + latch.countDown(); } @Test @@ -157,15 +172,18 @@ public class TcpNioConnectionWriteTests { ServerSocket server = ServerSocketFactory.getDefault() .createServerSocket(port); server.setSoTimeout(10000); + final CountDownLatch latch = new CountDownLatch(1); Thread t = new Thread(new Runnable() { + @Override public void run() { try { ByteArrayLengthHeaderSerializer serializer = new ByteArrayLengthHeaderSerializer(); AbstractConnectionFactory ccf = getClientConnectionFactory(true, port, serializer); TcpConnection connection = ccf.getConnection(); connection.send(MessageBuilder.withPayload(testString.getBytes()).build()); - Thread.sleep(1000000000L); - } catch (Exception e) { + latch.await(10, TimeUnit.SECONDS); + } + catch (Exception e) { e.printStackTrace(); } } @@ -181,6 +199,7 @@ public class TcpNioConnectionWriteTests { assertEquals(testString.length(), buffer.getInt()); assertEquals(testString, new String(buff, 4, testString.length())); server.close(); + latch.countDown(); } @Test @@ -190,16 +209,18 @@ public class TcpNioConnectionWriteTests { ServerSocket server = ServerSocketFactory.getDefault() .createServerSocket(port); server.setSoTimeout(10000); + final CountDownLatch latch = new CountDownLatch(1); Thread t = new Thread(new Runnable() { + @Override public void run() { try { ByteArrayStxEtxSerializer serializer = new ByteArrayStxEtxSerializer(); AbstractConnectionFactory ccf = getClientConnectionFactory(true, port, serializer); TcpConnection connection = ccf.getConnection(); connection.send(MessageBuilder.withPayload(testString.getBytes()).build()); - Thread.sleep(1000000000L); - Thread.sleep(1000000000L); - } catch (Exception e) { + latch.await(10, TimeUnit.SECONDS); + } + catch (Exception e) { e.printStackTrace(); } } @@ -215,6 +236,7 @@ public class TcpNioConnectionWriteTests { assertEquals(testString, new String(buff, 1, testString.length())); assertEquals(ByteArrayStxEtxSerializer.ETX, buff[testString.length() + 1]); server.close(); + latch.countDown(); } @Test @@ -224,16 +246,18 @@ public class TcpNioConnectionWriteTests { ServerSocket server = ServerSocketFactory.getDefault() .createServerSocket(port); server.setSoTimeout(10000); + final CountDownLatch latch = new CountDownLatch(1); Thread t = new Thread(new Runnable() { + @Override public void run() { try { ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer(); AbstractConnectionFactory ccf = getClientConnectionFactory(true, port, serializer); TcpConnection connection = ccf.getConnection(); connection.send(MessageBuilder.withPayload(testString.getBytes()).build()); - Thread.sleep(1000000000L); - Thread.sleep(1000000000L); - } catch (Exception e) { + latch.await(10, TimeUnit.SECONDS); + } + catch (Exception e) { e.printStackTrace(); } } @@ -249,6 +273,7 @@ public class TcpNioConnectionWriteTests { assertEquals('\r', buff[testString.length()]); assertEquals('\n', buff[testString.length() + 1]); server.close(); + latch.countDown(); } /** diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/serializer/DeserializationTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/serializer/DeserializationTests.java index 7f9f85ae61..edcbfd4af9 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/serializer/DeserializationTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/serializer/DeserializationTests.java @@ -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. @@ -22,10 +22,12 @@ import static org.junit.Assert.fail; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; +import java.util.concurrent.CountDownLatch; import javax.net.ServerSocketFactory; import org.junit.Test; + import org.springframework.core.serializer.DefaultDeserializer; import org.springframework.integration.ip.util.SocketTestUtils; import org.springframework.integration.test.util.SocketUtils; @@ -41,7 +43,7 @@ public class DeserializationTests { int port = SocketUtils.findAvailableServerSocket(); ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port); server.setSoTimeout(10000); - SocketTestUtils.testSendLength(port, null); + CountDownLatch done = SocketTestUtils.testSendLength(port, null); Socket socket = server.accept(); socket.setSoTimeout(5000); ByteArrayLengthHeaderSerializer serializer = new ByteArrayLengthHeaderSerializer(); @@ -52,6 +54,7 @@ public class DeserializationTests { assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING, new String(out)); server.close(); + done.countDown(); } @Test @@ -59,7 +62,7 @@ public class DeserializationTests { int port = SocketUtils.findAvailableServerSocket(); ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port); server.setSoTimeout(10000); - SocketTestUtils.testSendStxEtx(port, null); + CountDownLatch done = SocketTestUtils.testSendStxEtx(port, null); Socket socket = server.accept(); socket.setSoTimeout(5000); ByteArrayStxEtxSerializer serializer = new ByteArrayStxEtxSerializer(); @@ -70,6 +73,7 @@ public class DeserializationTests { assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING, new String(out)); server.close(); + done.countDown(); } @Test @@ -77,7 +81,7 @@ public class DeserializationTests { int port = SocketUtils.findAvailableServerSocket(); ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port); server.setSoTimeout(10000); - SocketTestUtils.testSendCrLf(port, null); + CountDownLatch done = SocketTestUtils.testSendCrLf(port, null); Socket socket = server.accept(); socket.setSoTimeout(5000); ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer(); @@ -88,6 +92,7 @@ public class DeserializationTests { assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING, new String(out)); server.close(); + done.countDown(); } @Test @@ -110,7 +115,7 @@ public class DeserializationTests { int port = SocketUtils.findAvailableServerSocket(); ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port); server.setSoTimeout(10000); - SocketTestUtils.testSendSerialized(port); + CountDownLatch done = SocketTestUtils.testSendSerialized(port); Socket socket = server.accept(); socket.setSoTimeout(5000); DefaultDeserializer deserializer = new DefaultDeserializer(); @@ -119,6 +124,7 @@ public class DeserializationTests { out = deserializer.deserialize(socket.getInputStream()); assertEquals("Data", SocketTestUtils.TEST_STRING, out); server.close(); + done.countDown(); } @Test @@ -126,7 +132,7 @@ public class DeserializationTests { int port = SocketUtils.findAvailableServerSocket(); ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port); server.setSoTimeout(10000); - SocketTestUtils.testSendLengthOverflow(port); + CountDownLatch done = SocketTestUtils.testSendLengthOverflow(port); Socket socket = server.accept(); socket.setSoTimeout(5000); ByteArrayLengthHeaderSerializer serializer = new ByteArrayLengthHeaderSerializer(); @@ -140,6 +146,7 @@ public class DeserializationTests { } } server.close(); + done.countDown(); } @Test @@ -147,7 +154,7 @@ public class DeserializationTests { int port = SocketUtils.findAvailableServerSocket(); ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port); server.setSoTimeout(10000); - SocketTestUtils.testSendStxEtxOverflow(port); + CountDownLatch done = SocketTestUtils.testSendStxEtxOverflow(port); Socket socket = server.accept(); socket.setSoTimeout(500); ByteArrayStxEtxSerializer serializer = new ByteArrayStxEtxSerializer(); @@ -161,6 +168,7 @@ public class DeserializationTests { } } server.close(); + done.countDown(); } @Test @@ -168,7 +176,7 @@ public class DeserializationTests { int port = SocketUtils.findAvailableServerSocket(); ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port); server.setSoTimeout(10000); - SocketTestUtils.testSendStxEtxOverflow(port); + CountDownLatch done = SocketTestUtils.testSendStxEtxOverflow(port); Socket socket = server.accept(); socket.setSoTimeout(5000); ByteArrayStxEtxSerializer serializer = new ByteArrayStxEtxSerializer(); @@ -183,6 +191,7 @@ public class DeserializationTests { } } server.close(); + done.countDown(); } @Test @@ -190,7 +199,7 @@ public class DeserializationTests { int port = SocketUtils.findAvailableServerSocket(); ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port); server.setSoTimeout(10000); - SocketTestUtils.testSendCrLfOverflow(port); + CountDownLatch latch = SocketTestUtils.testSendCrLfOverflow(port); Socket socket = server.accept(); socket.setSoTimeout(500); ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer(); @@ -204,6 +213,7 @@ public class DeserializationTests { } } server.close(); + latch.countDown(); } @Test @@ -211,7 +221,7 @@ public class DeserializationTests { int port = SocketUtils.findAvailableServerSocket(); ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port); server.setSoTimeout(10000); - SocketTestUtils.testSendCrLfOverflow(port); + CountDownLatch latch = SocketTestUtils.testSendCrLfOverflow(port); Socket socket = server.accept(); socket.setSoTimeout(5000); ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer(); @@ -219,13 +229,15 @@ public class DeserializationTests { try { serializer.deserialize(socket.getInputStream()); fail("Expected message length exceeded exception"); - } catch (IOException e) { + } + catch (IOException e) { if (!e.getMessage().startsWith("CRLF not found")) { e.printStackTrace(); fail("Unexpected IO Error:" + e.getMessage()); } } server.close(); + latch.countDown(); } } diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/serializer/SerializationTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/serializer/SerializationTests.java index e05374ee10..b51e1e38be 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/serializer/SerializationTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/serializer/SerializationTests.java @@ -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. @@ -24,11 +24,14 @@ import java.io.ObjectInputStream; import java.net.ServerSocket; import java.net.Socket; import java.nio.ByteBuffer; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import javax.net.ServerSocketFactory; import javax.net.SocketFactory; import org.junit.Test; + import org.springframework.core.serializer.DefaultSerializer; import org.springframework.integration.test.util.SocketUtils; @@ -44,7 +47,9 @@ public class SerializationTests { final String testString = "abcdef"; ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port); server.setSoTimeout(10000); + final CountDownLatch latch = new CountDownLatch(1); Thread t = new Thread(new Runnable() { + @Override public void run() { try { Socket socket = SocketFactory.getDefault().createSocket("localhost", port); @@ -52,8 +57,9 @@ public class SerializationTests { buffer.put(testString.getBytes()); ByteArrayLengthHeaderSerializer serializer = new ByteArrayLengthHeaderSerializer(); serializer.serialize(buffer.array(), socket.getOutputStream()); - Thread.sleep(1000000000L); - } catch (Exception e) { + latch.await(10, TimeUnit.SECONDS); + } + catch (Exception e) { e.printStackTrace(); } } @@ -69,6 +75,7 @@ public class SerializationTests { assertEquals(testString.length(), buffer.getInt()); assertEquals(testString, new String(buff, 4, testString.length())); server.close(); + latch.countDown(); } @Test @@ -77,7 +84,9 @@ public class SerializationTests { final String testString = "abcdef"; ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port); server.setSoTimeout(10000); + final CountDownLatch latch = new CountDownLatch(1); Thread t = new Thread(new Runnable() { + @Override public void run() { try { Socket socket = SocketFactory.getDefault().createSocket("localhost", port); @@ -85,8 +94,9 @@ public class SerializationTests { buffer.put(testString.getBytes()); ByteArrayStxEtxSerializer serializer = new ByteArrayStxEtxSerializer(); serializer.serialize(buffer.array(), socket.getOutputStream()); - Thread.sleep(1000000000L); - } catch (Exception e) { + latch.await(10, TimeUnit.SECONDS); + } + catch (Exception e) { e.printStackTrace(); } } @@ -102,6 +112,7 @@ public class SerializationTests { assertEquals(testString, new String(buff, 1, testString.length())); assertEquals(ByteArrayStxEtxSerializer.ETX, buff[testString.length() + 1]); server.close(); + latch.countDown(); } @Test @@ -110,7 +121,9 @@ public class SerializationTests { final String testString = "abcdef"; ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port); server.setSoTimeout(10000); + final CountDownLatch latch = new CountDownLatch(1); Thread t = new Thread(new Runnable() { + @Override public void run() { try { Socket socket = SocketFactory.getDefault().createSocket("localhost", port); @@ -118,8 +131,9 @@ public class SerializationTests { buffer.put(testString.getBytes()); ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer(); serializer.serialize(buffer.array(), socket.getOutputStream()); - Thread.sleep(1000000000L); - } catch (Exception e) { + latch.await(10, TimeUnit.SECONDS); + } + catch (Exception e) { e.printStackTrace(); } } @@ -135,6 +149,7 @@ public class SerializationTests { assertEquals('\r', buff[testString.length()]); assertEquals('\n', buff[testString.length() + 1]); server.close(); + latch.countDown(); } @Test @@ -143,7 +158,9 @@ public class SerializationTests { final String testString = "abcdef"; ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port); server.setSoTimeout(10000); + final CountDownLatch latch = new CountDownLatch(1); Thread t = new Thread(new Runnable() { + @Override public void run() { try { Socket socket = SocketFactory.getDefault().createSocket("localhost", port); @@ -152,8 +169,9 @@ public class SerializationTests { ByteArrayRawSerializer serializer = new ByteArrayRawSerializer(); serializer.serialize(buffer.array(), socket.getOutputStream()); socket.close(); - Thread.sleep(1000000000L); - } catch (Exception e) { + latch.await(10, TimeUnit.SECONDS); + } + catch (Exception e) { e.printStackTrace(); } } @@ -167,6 +185,7 @@ public class SerializationTests { readFully(is, buff); assertEquals(testString, new String(buff, 0, testString.length())); assertEquals(-1, buff[testString.length()]); + latch.countDown(); server.close(); } @@ -176,15 +195,18 @@ public class SerializationTests { final String testString = "abcdef"; ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port); server.setSoTimeout(10000); + final CountDownLatch latch = new CountDownLatch(1); Thread t = new Thread(new Runnable() { + @Override public void run() { try { Socket socket = SocketFactory.getDefault().createSocket("localhost", port); DefaultSerializer serializer = new DefaultSerializer(); serializer.serialize(testString, socket.getOutputStream()); serializer.serialize(testString, socket.getOutputStream()); - Thread.sleep(1000000000L); - } catch (Exception e) { + latch.await(10, TimeUnit.SECONDS); + } + catch (Exception e) { e.printStackTrace(); } } @@ -198,6 +220,7 @@ public class SerializationTests { assertEquals(testString, ois.readObject()); ois = new ObjectInputStream(is); assertEquals(testString, ois.readObject()); + latch.countDown(); server.close(); } diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/DatagramPacketSendingHandlerTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/DatagramPacketSendingHandlerTests.java index 8a1b157e31..112e0f3b95 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/DatagramPacketSendingHandlerTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/DatagramPacketSendingHandlerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 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. @@ -33,10 +33,11 @@ import java.util.concurrent.TimeUnit; import org.apache.commons.logging.LogFactory; import org.junit.Ignore; import org.junit.Test; -import org.springframework.messaging.Message; + import org.springframework.integration.ip.IpHeaders; import org.springframework.integration.support.MessageBuilder; import org.springframework.integration.test.util.SocketUtils; +import org.springframework.messaging.Message; /** * @author Mark Fisher @@ -54,6 +55,7 @@ public class DatagramPacketSendingHandlerTests { final DatagramPacket receivedPacket = new DatagramPacket(buffer, buffer.length); final CountDownLatch latch = new CountDownLatch(1); Executors.newSingleThreadExecutor().execute(new Runnable() { + @Override public void run() { try { DatagramSocket socket = new DatagramSocket(testPort); @@ -78,7 +80,7 @@ public class DatagramPacketSendingHandlerTests { byte[] dest = new byte[length]; System.arraycopy(src, offset, dest, 0, length); assertEquals(payload, new String(dest)); - handler.shutDown(); + handler.stop(); } @Test @@ -97,7 +99,9 @@ public class DatagramPacketSendingHandlerTests { new UnicastSendingMessageHandler("localhost", testPort, true, true, "localhost", ackPort, 5000); handler.afterPropertiesSet(); + handler.start(); Executors.newSingleThreadExecutor().execute(new Runnable() { + @Override public void run() { try { DatagramSocket socket = new DatagramSocket(testPort); @@ -132,7 +136,7 @@ public class DatagramPacketSendingHandlerTests { byte[] dest = new byte[6]; System.arraycopy(src, offset+length-6, dest, 0, 6); assertEquals(payload, new String(dest)); - handler.shutDown(); + handler.stop(); } @Test @@ -144,6 +148,7 @@ public class DatagramPacketSendingHandlerTests { final CountDownLatch latch1 = new CountDownLatch(2); final CountDownLatch latch2 = new CountDownLatch(2); Runnable catcher = new Runnable() { + @Override public void run() { try { byte[] buffer = new byte[8]; @@ -183,7 +188,7 @@ public class DatagramPacketSendingHandlerTests { MulticastSendingMessageHandler handler = new MulticastSendingMessageHandler(multicastAddress, testPort); handler.handleMessage(MessageBuilder.withPayload(payload).build()); assertTrue(latch2.await(3000, TimeUnit.MILLISECONDS)); - handler.shutDown(); + handler.stop(); } @Test @@ -200,6 +205,7 @@ public class DatagramPacketSendingHandlerTests { final CountDownLatch latch1 = new CountDownLatch(2); final CountDownLatch latch2 = new CountDownLatch(2); Runnable catcher = new Runnable() { + @Override public void run() { try { byte[] buffer = new byte[1000]; @@ -249,9 +255,11 @@ public class DatagramPacketSendingHandlerTests { new MulticastSendingMessageHandler(multicastAddress, testPort, true, true, "localhost", ackPort, 500000); handler.setMinAcksForSuccess(2); + handler.afterPropertiesSet(); + handler.start(); handler.handleMessage(MessageBuilder.withPayload(payload).build()); assertTrue(latch2.await(10000, TimeUnit.MILLISECONDS)); - handler.shutDown(); + handler.stop(); } } diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/MultiClientTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/MultiClientTests.java index 067dd4d359..0f6d9d4a6e 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/MultiClientTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/MultiClientTests.java @@ -16,15 +16,18 @@ package org.springframework.integration.ip.udp; import static org.junit.Assert.assertNotNull; -import org.junit.Assert; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.junit.Assert; import org.junit.Ignore; import org.junit.Test; -import org.springframework.messaging.Message; + import org.springframework.integration.channel.QueueChannel; import org.springframework.integration.ip.util.SocketTestUtils; import org.springframework.integration.support.MessageBuilder; import org.springframework.integration.test.util.SocketUtils; +import org.springframework.messaging.Message; /** @@ -45,7 +48,8 @@ import org.springframework.integration.test.util.SocketUtils; public class MultiClientTests { @SuppressWarnings("unchecked") - @Test @Ignore + @Test + @Ignore public void testNoAck() throws Exception { final String payload = largePayload(1000); final UnicastReceivingChannelAdapter adapter = @@ -57,15 +61,24 @@ public class MultiClientTests { adapter.start(); final QueueChannel queueIn = new QueueChannel(1000); SocketTestUtils.waitListening(adapter); + + final AtomicBoolean done = new AtomicBoolean(); + for (int i = 0; i < drivers; i++) { Thread t = new Thread( new Runnable() { + @Override public void run() { UnicastSendingMessageHandler sender = new UnicastSendingMessageHandler( "localhost", adapter.getPort()); + sender.start(); while (true) { Message message = queueIn.receive(); sender.handleMessage(message); + if (done.get()) { + break; + } } + sender.stop(); }}); t.setDaemon(true); t.start(); @@ -79,12 +92,13 @@ public class MultiClientTests { Assert.assertEquals(payload, new String(messageOut.getPayload())); } adapter.stop(); + done.set(true); } @SuppressWarnings("unchecked") - @Test @Ignore + @Test + @Ignore public void testAck() throws Exception { - Thread.sleep(1000); final String payload = largePayload(1000); final UnicastReceivingChannelAdapter adapter = new UnicastReceivingChannelAdapter(SocketUtils.findAvailableUdpSocket(), false); @@ -95,19 +109,28 @@ public class MultiClientTests { adapter.start(); final QueueChannel queueIn = new QueueChannel(1000); SocketTestUtils.waitListening(adapter); + + final AtomicBoolean done = new AtomicBoolean(); + for (int i = 0; i < drivers; i++) { final int j = i; Thread t = new Thread( new Runnable() { + @Override public void run() { UnicastSendingMessageHandler sender = new UnicastSendingMessageHandler( "localhost", adapter.getPort(), false, true, "localhost", SocketUtils.findAvailableUdpSocket(adapter.getPort() + j + 1000), 10000); + sender.start(); while (true) { Message message = queueIn.receive(); sender.handleMessage(message); + if (done.get()) { + break; + } } + sender.stop(); }}); t.setDaemon(true); t.start(); @@ -121,12 +144,13 @@ public class MultiClientTests { Assert.assertEquals(payload, new String(messageOut.getPayload())); } adapter.stop(); + done.set(true); } @SuppressWarnings("unchecked") - @Test @Ignore + @Test + @Ignore public void testAckWithLength() throws Exception { - Thread.sleep(1000); final String payload = largePayload(1000); final UnicastReceivingChannelAdapter adapter = new UnicastReceivingChannelAdapter(SocketUtils.findAvailableUdpSocket(), true); @@ -137,19 +161,28 @@ public class MultiClientTests { adapter.start(); final QueueChannel queueIn = new QueueChannel(1000); SocketTestUtils.waitListening(adapter); + + final AtomicBoolean done = new AtomicBoolean(); + for (int i = 0; i < drivers; i++) { final int j = i; Thread t = new Thread( new Runnable() { + @Override public void run() { UnicastSendingMessageHandler sender = new UnicastSendingMessageHandler( "localhost", adapter.getPort(), true, true, "localhost", SocketUtils.findAvailableUdpSocket(adapter.getPort() + j + 1100), 10000); + sender.start(); while (true) { Message message = queueIn.receive(); sender.handleMessage(message); + if (done.get()) { + break; + } } + sender.stop(); }}); t.setDaemon(true); t.start(); @@ -163,6 +196,7 @@ public class MultiClientTests { Assert.assertEquals(payload, new String(messageOut.getPayload())); } adapter.stop(); + done.set(true); } private String largePayload(int n) { diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/SyslogdTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/SyslogdTests.java index edad25436e..30afa46a1b 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/SyslogdTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/SyslogdTests.java @@ -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. @@ -29,6 +29,6 @@ public class SyslogdTests { AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("SyslogdTests-context.xml", SyslogdTests.class); System.out.println("Hit enter to terminate"); System.in.read(); - ctx.destroy(); + ctx.close(); } } diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/UdpChannelAdapterTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/UdpChannelAdapterTests.java index 2fc2523c5c..fc1901b3cd 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/UdpChannelAdapterTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/UdpChannelAdapterTests.java @@ -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. @@ -32,15 +32,16 @@ import java.util.concurrent.atomic.AtomicReference; import org.apache.commons.logging.LogFactory; import org.junit.Ignore; import org.junit.Test; -import org.springframework.messaging.Message; + import org.springframework.integration.channel.DirectChannel; import org.springframework.integration.channel.QueueChannel; -import org.springframework.messaging.SubscribableChannel; import org.springframework.integration.handler.ServiceActivatingHandler; import org.springframework.integration.ip.IpHeaders; import org.springframework.integration.ip.util.SocketTestUtils; import org.springframework.integration.support.MessageBuilder; import org.springframework.integration.test.util.SocketUtils; +import org.springframework.messaging.Message; +import org.springframework.messaging.SubscribableChannel; /** * @@ -65,9 +66,12 @@ public class UdpChannelAdapterTests { DatagramPacketMessageMapper mapper = new DatagramPacketMessageMapper(); DatagramPacket packet = mapper.fromMessage(message); packet.setSocketAddress(new InetSocketAddress("localhost", port)); - new DatagramSocket(SocketUtils.findAvailableUdpSocket()).send(packet); + DatagramSocket datagramSocket = new DatagramSocket(SocketUtils.findAvailableUdpSocket()); + datagramSocket.send(packet); + datagramSocket.close(); Message receivedMessage = (Message) channel.receive(2000); assertEquals(new String(message.getPayload()), new String(receivedMessage.getPayload())); + adapter.stop(); } @SuppressWarnings("unchecked") @@ -91,6 +95,7 @@ public class UdpChannelAdapterTests { final CountDownLatch replyReceivedLatch = new CountDownLatch(1); //main thread sends the reply using the headers, this thread will receive it Executors.newSingleThreadExecutor().execute(new Runnable() { + @Override public void run() { DatagramPacket answer = new DatagramPacket(new byte[2000], 2000); try { @@ -112,11 +117,15 @@ public class UdpChannelAdapterTests { (String) receivedMessage.getHeaders().get(IpHeaders.IP_ADDRESS), (Integer) receivedMessage.getHeaders().get(IpHeaders.PORT))); assertTrue(receiverReadyLatch.await(10, TimeUnit.SECONDS)); - new DatagramSocket().send(reply); + DatagramSocket datagramSocket = new DatagramSocket(); + datagramSocket.send(reply); assertTrue(replyReceivedLatch.await(10, TimeUnit.SECONDS)); DatagramPacket answerPacket = theAnswer.get(); assertNotNull(answerPacket); assertEquals(replyString, new String(answerPacket.getData(), 0, answerPacket.getLength())); + datagramSocket.close(); + socket.close(); + adapter.stop(); } @SuppressWarnings("unchecked") @@ -139,10 +148,13 @@ public class UdpChannelAdapterTests { SocketUtils.findAvailableUdpSocket(), 5000); // handler.setLocalAddress(whichNic); handler.afterPropertiesSet(); + handler.start(); Message message = MessageBuilder.withPayload("ABCD".getBytes()).build(); handler.handleMessage(message); Message receivedMessage = (Message) channel.receive(2000); assertEquals(new String(message.getPayload()), new String(receivedMessage.getPayload())); + adapter.stop(); + handler.stop(); } @SuppressWarnings("unchecked") @@ -165,11 +177,14 @@ public class UdpChannelAdapterTests { DatagramPacketMessageMapper mapper = new DatagramPacketMessageMapper(); DatagramPacket packet = mapper.fromMessage(message); packet.setSocketAddress(new InetSocketAddress("225.6.7.8", port)); - new DatagramSocket(0, Inet4Address.getByName(nic)).send(packet); + DatagramSocket datagramSocket = new DatagramSocket(0, Inet4Address.getByName(nic)); + datagramSocket.send(packet); + datagramSocket.close(); Message receivedMessage = (Message) channel.receive(2000); assertNotNull(receivedMessage); assertEquals(new String(message.getPayload()), new String(receivedMessage.getPayload())); + adapter.stop(); } @SuppressWarnings("unchecked") @@ -196,6 +211,7 @@ public class UdpChannelAdapterTests { Message receivedMessage = (Message) channel.receive(2000); assertNotNull(receivedMessage); assertEquals(new String(message.getPayload()), new String(receivedMessage.getPayload())); + adapter.stop(); } @Test @@ -217,10 +233,13 @@ public class UdpChannelAdapterTests { DatagramPacketMessageMapper mapper = new DatagramPacketMessageMapper(); DatagramPacket packet = mapper.fromMessage(message); packet.setSocketAddress(new InetSocketAddress("localhost", port)); - new DatagramSocket(SocketUtils.findAvailableUdpSocket()).send(packet); + DatagramSocket datagramSocket = new DatagramSocket(SocketUtils.findAvailableUdpSocket()); + datagramSocket.send(packet); + datagramSocket.close(); Message receivedMessage = errorChannel.receive(2000); assertNotNull(receivedMessage); assertEquals("Failed", ((Exception) receivedMessage.getPayload()).getCause().getMessage()); + adapter.stop(); } private class FailingService { diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/UdpMulticastEndToEndTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/UdpMulticastEndToEndTests.java index b6d2dc3ea6..b3af7223dc 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/UdpMulticastEndToEndTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/UdpMulticastEndToEndTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 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. @@ -122,6 +122,7 @@ public class UdpMulticastEndToEndTests implements Runnable { /** * Instantiate the receiving context */ + @Override @SuppressWarnings("unchecked") public void run() { AbstractApplicationContext ctx = new ClassPathXmlApplicationContext( @@ -146,6 +147,7 @@ public class UdpMulticastEndToEndTests implements Runnable { } } ctx.stop(); + ctx.close(); } diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/UdpUnicastEndToEndTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/UdpUnicastEndToEndTests.java index 4e01756a77..614d457abe 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/UdpUnicastEndToEndTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/UdpUnicastEndToEndTests.java @@ -143,7 +143,9 @@ public class UdpUnicastEndToEndTests implements Runnable { * Instantiate the receiving context */ @SuppressWarnings("unchecked") + @Override public void run() { + @SuppressWarnings("resource") AbstractApplicationContext ctx = new ClassPathXmlApplicationContext( "testIp-in-context.xml", UdpUnicastEndToEndTests.class); UnicastReceivingChannelAdapter inbound = ctx.getBean(UnicastReceivingChannelAdapter.class); @@ -155,7 +157,8 @@ public class UdpUnicastEndToEndTests implements Runnable { throw new RuntimeException("Failed to start listening"); } } - } catch (Exception e) { } + } + catch (Exception e) { } while (okToRun) { try { readyToReceive.countDown(); @@ -179,6 +182,7 @@ public class UdpUnicastEndToEndTests implements Runnable { } } ctx.stop(); + ctx.close(); } diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/testIp-out-multicast-context.xml b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/testIp-out-multicast-context.xml index e449e17b22..96e938417a 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/testIp-out-multicast-context.xml +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/testIp-out-multicast-context.xml @@ -14,9 +14,7 @@ http://www.springframework.org/schema/integration/ip/spring-integration-ip.xsd"> - - - + diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/util/SocketTestUtils.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/util/SocketTestUtils.java index 8efdca0271..4b7d029d06 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/util/SocketTestUtils.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/util/SocketTestUtils.java @@ -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. @@ -16,6 +16,7 @@ package org.springframework.integration.ip.util; +import java.io.IOException; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.net.InetAddress; @@ -23,6 +24,7 @@ import java.net.Socket; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -46,11 +48,14 @@ public class SocketTestUtils { * Sends a message in two chunks with a preceding length. Two such messages are sent. * @param latch If not null, await until counted down before sending second chunk. */ - public static void testSendLength(final int port, final CountDownLatch latch) { + public static CountDownLatch testSendLength(final int port, final CountDownLatch latch) { + final CountDownLatch testCompleteLatch = new CountDownLatch(1); Thread thread = new Thread(new Runnable() { + @Override public void run() { + Socket socket = null; try { - Socket socket = new Socket(InetAddress.getByName("localhost"), port); + socket = new Socket(InetAddress.getByName("localhost"), port); for (int i = 0; i < 2; i++) { byte[] len = new byte[4]; ByteBuffer.wrap(len).putInt(TEST_STRING.length() * 2); @@ -65,48 +70,74 @@ public class SocketTestUtils { socket.getOutputStream().write(TEST_STRING.getBytes()); logger.debug(i + " Wrote second part"); } - Thread.sleep(1000000000L); // wait forever, but we're a daemon - } catch (Exception e) { + testCompleteLatch.await(10, TimeUnit.SECONDS); + } + catch (Exception e) { e.printStackTrace(); } + finally { + if (socket != null) { + try { + socket.close(); + } + catch (IOException e) { } + } + } } }); thread.setDaemon(true); thread.start(); + return testCompleteLatch; } /** * Sends a message with a bad length part, causing an overflow on the receiver. */ - public static void testSendLengthOverflow(final int port) { + public static CountDownLatch testSendLengthOverflow(final int port) { + final CountDownLatch testCompleteLatch = new CountDownLatch(1); Thread thread = new Thread(new Runnable() { + @Override public void run() { + Socket socket = null; try { - Socket socket = new Socket(InetAddress.getByName("localhost"), port); + socket = new Socket(InetAddress.getByName("localhost"), port); byte[] len = new byte[4]; ByteBuffer.wrap(len).putInt(Integer.MAX_VALUE); socket.getOutputStream().write(len); socket.getOutputStream().write(TEST_STRING.getBytes()); - Thread.sleep(1000000000L); // wait forever, but we're a daemon - } catch (Exception e) { + testCompleteLatch.await(10, TimeUnit.SECONDS); + } + catch (Exception e) { e.printStackTrace(); } + finally { + if (socket != null) { + try { + socket.close(); + } + catch (IOException e) { } + } + } } }); thread.setDaemon(true); thread.start(); + return testCompleteLatch; } /** * Test for reassembly of completely fragmented message; sends * 6 bytes 500ms apart. */ - public static void testSendFragmented(final int port, final int howMany, final boolean noDelay) { + public static CountDownLatch testSendFragmented(final int port, final int howMany, final boolean noDelay) { + final CountDownLatch testCompleteLatch = new CountDownLatch(1); Thread thread = new Thread(new Runnable() { + @Override public void run() { + Socket socket = null; try { logger.debug("Connecting to " + port); - Socket socket = new Socket(InetAddress.getByName("localhost"), port); + socket = new Socket(InetAddress.getByName("localhost"), port); OutputStream os = socket.getOutputStream(); for (int i = 0; i < howMany; i++) { writeByte(os, 0, noDelay); @@ -116,14 +147,24 @@ public class SocketTestUtils { writeByte(os, 'x', noDelay); writeByte(os, 'x', noDelay); } - Thread.sleep(1000000000L); // wait forever, but we're a daemon - } catch (Exception e) { + testCompleteLatch.await(10, TimeUnit.SECONDS); + } + catch (Exception e) { e.printStackTrace(); } + finally { + if (socket != null) { + try { + socket.close(); + } + catch (IOException e) { } + } + } } }); thread.setDaemon(true); thread.start(); + return testCompleteLatch; } private static void writeByte(OutputStream os, int b, boolean noDelay) throws Exception { @@ -139,11 +180,14 @@ public class SocketTestUtils { * Sends a STX/ETX message in two chunks. Two such messages are sent. * @param latch If not null, await until counted down before sending second chunk. */ - public static void testSendStxEtx(final int port, final CountDownLatch latch) { + public static CountDownLatch testSendStxEtx(final int port, final CountDownLatch latch) { + final CountDownLatch testCompleteLatch = new CountDownLatch(1); Thread thread = new Thread(new Runnable() { + @Override public void run() { + Socket socket = null; try { - Socket socket = new Socket(InetAddress.getByName("localhost"), port); + socket = new Socket(InetAddress.getByName("localhost"), port); OutputStream outputStream = socket.getOutputStream(); for (int i = 0; i < 2; i++) { writeByte(outputStream, 0x02, true); @@ -158,46 +202,74 @@ public class SocketTestUtils { logger.debug(i + " Wrote second part"); writeByte(outputStream, 0x03, true); } - Thread.sleep(1000000000L); // wait forever, but we're a daemon - } catch (Exception e) { + testCompleteLatch.await(10, TimeUnit.SECONDS); + } + catch (Exception e) { e.printStackTrace(); } + finally { + if (socket != null) { + try { + socket.close(); + } + catch (IOException e) { } + } + } } }); thread.setDaemon(true); thread.start(); + return testCompleteLatch; } /** * Sends a large STX/ETX message with no ETX */ - public static void testSendStxEtxOverflow(final int port) { + public static CountDownLatch testSendStxEtxOverflow(final int port) { + final CountDownLatch testCompleteLatch = new CountDownLatch(1); Thread thread = new Thread(new Runnable() { + @Override public void run() { + Socket socket = null; try { - Socket socket = new Socket(InetAddress.getByName("localhost"), port); + socket = new Socket(InetAddress.getByName("localhost"), port); OutputStream outputStream = socket.getOutputStream(); writeByte(outputStream, 0x02, true); for (int i = 0; i < 1500; i++) { writeByte(outputStream, 'x', true); } - Thread.sleep(1000000000L); // wait forever, but we're a daemon - } catch (Exception e) { } + testCompleteLatch.await(10, TimeUnit.SECONDS); + } + catch (Exception e) { + e.printStackTrace(); + } + finally { + if (socket != null) { + try { + socket.close(); + } + catch (IOException e) { } + } + } } }); thread.setDaemon(true); thread.start(); + return testCompleteLatch; } /** * Sends a message +CRLF in two chunks. Two such messages are sent. * @param latch If not null, await until counted down before sending second chunk. */ - public static void testSendCrLf(final int port, final CountDownLatch latch) { + public static CountDownLatch testSendCrLf(final int port, final CountDownLatch latch) { + final CountDownLatch testCompleteLatch = new CountDownLatch(1); Thread thread = new Thread(new Runnable() { + @Override public void run() { + Socket socket = null; try { - Socket socket = new Socket(InetAddress.getByName("localhost"), port); + socket = new Socket(InetAddress.getByName("localhost"), port); OutputStream outputStream = socket.getOutputStream(); for (int i = 0; i < 2; i++) { outputStream.write(TEST_STRING.getBytes()); @@ -212,14 +284,24 @@ public class SocketTestUtils { writeByte(outputStream, '\r', true); writeByte(outputStream, '\n', true); } - Thread.sleep(1000000000L); // wait forever, but we're a daemon - } catch (Exception e) { + testCompleteLatch.await(10, TimeUnit.SECONDS); + } + catch (Exception e) { e.printStackTrace(); } + finally { + if (socket != null) { + try { + socket.close(); + } + catch (IOException e) { } + } + } } }); thread.setDaemon(true); thread.start(); + return testCompleteLatch; } /** @@ -228,6 +310,7 @@ public class SocketTestUtils { */ public static void testSendCrLfSingle(final int port, final CountDownLatch latch) { Thread thread = new Thread(new Runnable() { + @Override public void run() { try { Socket socket = new Socket(InetAddress.getByName("localhost"), port); @@ -240,7 +323,8 @@ public class SocketTestUtils { latch.await(); } socket.close(); - } catch (Exception e) { + } + catch (Exception e) { e.printStackTrace(); } } @@ -254,6 +338,7 @@ public class SocketTestUtils { */ public static void testSendRaw(final int port) { Thread thread = new Thread(new Runnable() { + @Override public void run() { try { Socket socket = new Socket(InetAddress.getByName("localhost"), port); @@ -261,7 +346,8 @@ public class SocketTestUtils { outputStream.write(TEST_STRING.getBytes()); outputStream.write(TEST_STRING.getBytes()); socket.close(); - } catch (Exception e) { + } + catch (Exception e) { e.printStackTrace(); } } @@ -273,11 +359,14 @@ public class SocketTestUtils { * Sends two serialized objects over the same socket. * @param port */ - public static void testSendSerialized(final int port) { + public static CountDownLatch testSendSerialized(final int port) { + final CountDownLatch testCompleteLatch = new CountDownLatch(1); Thread thread = new Thread(new Runnable() { + @Override public void run() { + Socket socket = null; try { - Socket socket = new Socket(InetAddress.getByName("localhost"), port); + socket = new Socket(InetAddress.getByName("localhost"), port); OutputStream outputStream = socket.getOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(outputStream); oos.writeObject(TEST_STRING); @@ -285,21 +374,33 @@ public class SocketTestUtils { oos = new ObjectOutputStream(outputStream); oos.writeObject(TEST_STRING); oos.flush(); - Thread.sleep(1000000000L); // wait forever, but we're a daemon - } catch (Exception e) { + testCompleteLatch.await(10, TimeUnit.SECONDS); + } + catch (Exception e) { e.printStackTrace(); } + finally { + if (socket != null) { + try { + socket.close(); + } + catch (IOException e) { } + } + } } }); thread.setDaemon(true); thread.start(); + return testCompleteLatch; } /** * Sends a large CRLF message with no CRLF. */ - public static void testSendCrLfOverflow(final int port) { + public static CountDownLatch testSendCrLfOverflow(final int port) { + final CountDownLatch testCompleteLatch = new CountDownLatch(1); Thread thread = new Thread(new Runnable() { + @Override public void run() { try { Socket socket = new Socket(InetAddress.getByName("localhost"), port); @@ -307,12 +408,15 @@ public class SocketTestUtils { for (int i = 0; i < 1500; i++) { writeByte(outputStream, 'x', true); } - Thread.sleep(1000000000L); // wait forever, but we're a daemon - } catch (Exception e) { } + testCompleteLatch.await(10, TimeUnit.SECONDS); + socket.close(); + } + catch (Exception e) { } } }); thread.setDaemon(true); thread.start(); + return testCompleteLatch; } public static void setLocalNicIfPossible( diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcExecutor.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcExecutor.java index ea3926ec67..c41c726804 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcExecutor.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcExecutor.java @@ -490,19 +490,6 @@ public class StoredProcExecutor implements BeanFactoryAware, InitializingBean { this.usePayloadAsParameterSource = usePayloadAsParameterSource; } - /** - * Indicates whether a Stored Procedure or a Function is being executed. - * The default value is false. - * - * @param isFunction If set to true an Sql Function is executed rather than a Stored Procedure. - * - * @deprecated Please use {@link #setIsFunction(boolean)} instead. - */ - @Deprecated - public void setFunction(boolean isFunction) { - this.isFunction = isFunction; - } - /** * Indicates whether a Stored Procedure or a Function is being executed. * The default value is false. diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcMessageHandler.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcMessageHandler.java index 563b9e2f96..024daadbff 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcMessageHandler.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcMessageHandler.java @@ -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. You may obtain a copy of the License at @@ -13,19 +13,12 @@ package org.springframework.integration.jdbc; -import java.util.List; import java.util.Map; -import javax.sql.DataSource; - import org.springframework.beans.factory.InitializingBean; -import org.springframework.expression.Expression; -import org.springframework.messaging.Message; import org.springframework.integration.handler.AbstractMessageHandler; import org.springframework.integration.jdbc.storedproc.ProcedureParameter; -import org.springframework.jdbc.core.SqlParameter; -import org.springframework.jdbc.core.simple.SimpleJdbcCall; -import org.springframework.jdbc.core.simple.SimpleJdbcCallOperations; +import org.springframework.messaging.Message; import org.springframework.util.Assert; @@ -55,27 +48,6 @@ public class StoredProcMessageHandler extends AbstractMessageHandler implements private final StoredProcExecutor executor; - /** - * Constructor taking {@link DataSource} from which the DB Connection can be - * obtained and the name of the stored procedure or function to - * execute to retrieve new rows. - * - * @param dataSource Must not be null. - * @param storedProcedureName The name of the Stored Procedure or Function. Must not be null. - * - * @deprecated Since 2.2 use the constructor that expects a {@link StoredProcExecutor} instead - */ - @Deprecated - public StoredProcMessageHandler(DataSource dataSource, String storedProcedureName) { - - Assert.notNull(dataSource, "dataSource must not be null."); - Assert.hasText(storedProcedureName, "storedProcedureName must not be null and cannot be empty."); - - this.executor = new StoredProcExecutor(dataSource); - this.executor.setStoredProcedureName(storedProcedureName); - - } - /** * * Constructor passing in the {@link StoredProcExecutor}. @@ -84,22 +56,11 @@ public class StoredProcMessageHandler extends AbstractMessageHandler implements * */ public StoredProcMessageHandler(StoredProcExecutor storedProcExecutor) { - Assert.notNull(storedProcExecutor, "storedProcExecutor must not be null."); this.executor = storedProcExecutor; } - /** - * Verifies parameters, sets the parameters on {@link SimpleJdbcCallOperations} - * and ensures the appropriate {@link SqlParameterSourceFactory} is defined - * when {@link ProcedureParameter} are passed in. - */ - @Override - protected void onInit() throws Exception { - super.onInit(); - }; - /** * Executes the Stored procedure, delegates to executeStoredProcedure(...). * Any return values from the Stored procedure are ignored. @@ -115,121 +76,11 @@ public class StoredProcMessageHandler extends AbstractMessageHandler implements if (resultMap != null && !resultMap.isEmpty()) { logger.debug(String.format("The StoredProcMessageHandler ignores return " - + "values, but the called Stored Procedure returned data: '%s'", executor.getStoredProcedureName(), resultMap)); + + "values, but the called Stored Procedure '%s' returned data: '%s'", executor.getStoredProcedureName(), resultMap)); } } } - /** - * The name of the Stored Procedure or Stored Function to be executed. - * If {@link StoredProcExecutor#isFunction} is set to "true", then this - * property specifies the Stored Function name. - * - * Alternatively you can also specify the Stored Procedure name via - * {@link StoredProcExecutor#setStoredProcedureNameExpression(Expression)}. - * - * @param storedProcedureName Must not be null and must not be empty - * - * @see StoredProcExecutor#setStoredProcedureNameExpression(Expression) - * - * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} - * - * @see StoredProcExecutor#setStoredProcedureName(String) - */ - @Deprecated - public void setStoredProcedureName(String storedProcedureName) { - this.executor.setStoredProcedureName(storedProcedureName); - } - - /** - * For fully supported databases, the underlying {@link SimpleJdbcCall} can - * retrieve the parameter information for the to be invoked Stored Procedure - * from the JDBC Meta-data. However, if the used database does not support - * meta data lookups or if you like to provide customized parameter definitions, - * this flag can be set to true. It defaults to false. - * - * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} - * - * @see StoredProcExecutor#setIgnoreColumnMetaData(boolean) - */ - @Deprecated - public void setIgnoreColumnMetaData(boolean ignoreColumnMetaData) { - this.executor.setIgnoreColumnMetaData(ignoreColumnMetaData); - } - - /** - * Custom Stored Procedure parameters that may contain static values - * or Strings representing an {@link Expression}. - * - * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} - * - * @see StoredProcExecutor#setProcedureParameters(List) - */ - @Deprecated - public void setProcedureParameters(List procedureParameters) { - this.executor.setProcedureParameters(procedureParameters); - } - - /** - * If your database system is not fully supported by Spring and thus obtaining - * parameter definitions from the JDBC Meta-data is not possible, you must define - * the {@link SqlParameter} explicitly. - * - * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} - * - * @see StoredProcExecutor#setSqlParameters(List) - */ - @Deprecated - public void setSqlParameters(List sqlParameters) { - this.executor.setSqlParameters(sqlParameters); - } - - /** - * Provides the ability to set a custom {@link SqlParameterSourceFactory}. - * Keep in mind that if {@link ProcedureParameter} are set explicitly and - * you would like to provide a custom {@link SqlParameterSourceFactory}, - * then you must provide an instance of {@link ExpressionEvaluatingSqlParameterSourceFactory}. - * - * If not the SqlParameterSourceFactory will be replaced by the default - * {@link ExpressionEvaluatingSqlParameterSourceFactory}. - * - * @param sqlParameterSourceFactory - * - * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} - * - * @see StoredProcExecutor#setSqlParameterSourceFactory(SqlParameterSourceFactory) - */ - @Deprecated - public void setSqlParameterSourceFactory(SqlParameterSourceFactory sqlParameterSourceFactory) { - this.executor.setSqlParameterSourceFactory(sqlParameterSourceFactory); - } - - /** - * If set to 'true', the payload of the Message will be used as a source for - * providing parameters. If false the entire Message will be available as a - * source for parameters. - * - * If no {@link ProcedureParameter} are passed in, this property will default to - * 'true'. This means that using a default {@link BeanPropertySqlParameterSourceFactory} - * the bean properties of the payload will be used as a source for parameter values for - * the to-be-executed Stored Procedure or Function. - * - * However, if {@link ProcedureParameter} are passed in, then this property - * will by default evaluate to 'false'. {@link ProcedureParameter} allow for - * SpEl Expressions to be provided and therefore it is highly beneficial to - * have access to the entire {@link Message}. - * - * @param usePayloadAsParameterSource If false the entire {@link Message} is used as parameter source. - * - * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} - * - * @see StoredProcExecutor#setUsePayloadAsParameterSource(boolean) - */ - @Deprecated - public void setUsePayloadAsParameterSource(boolean usePayloadAsParameterSource) { - this.executor.setUsePayloadAsParameterSource(usePayloadAsParameterSource); - } - } diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcOutboundGateway.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcOutboundGateway.java index f3ff695d87..e305180f18 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcOutboundGateway.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcOutboundGateway.java @@ -17,24 +17,13 @@ package org.springframework.integration.jdbc; import java.sql.CallableStatement; -import java.util.List; import java.util.Map; -import javax.sql.DataSource; - -import org.springframework.expression.Expression; -import org.springframework.messaging.Message; import org.springframework.integration.MessageHandlingException; -import org.springframework.messaging.MessagingException; import org.springframework.integration.handler.AbstractReplyProducingMessageHandler; -import org.springframework.integration.jdbc.storedproc.ProcedureParameter; import org.springframework.integration.support.MessageBuilder; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.RowMapper; -import org.springframework.jdbc.core.SqlOutParameter; -import org.springframework.jdbc.core.SqlParameter; -import org.springframework.jdbc.core.simple.SimpleJdbcCall; -import org.springframework.jdbc.core.simple.SimpleJdbcCallOperations; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessagingException; import org.springframework.util.Assert; /** @@ -48,27 +37,6 @@ public class StoredProcOutboundGateway extends AbstractReplyProducingMessageHand private volatile boolean expectSingleResult = false; - /** - * Constructor taking {@link DataSource} from which the DB Connection can be - * obtained and the name of the stored procedure or function to - * execute to retrieve new rows. - * - * @param dataSource used to create a {@link SimpleJdbcCall} instance - * @param storedProcedureName Must not be null. - * - * @deprecated Since 2.2 use the constructor that expects a {@link StoredProcExecutor} instead - */ - @Deprecated - public StoredProcOutboundGateway(DataSource dataSource, String storedProcedureName) { - - Assert.notNull(dataSource, "dataSource must not be null."); - Assert.hasText(storedProcedureName, "storedProcedureName must not be null and cannot be empty."); - - this.executor = new StoredProcExecutor(dataSource); - this.executor.setStoredProcedureName(storedProcedureName); - - } - /** * Constructor taking {@link StoredProcExecutor}. * @@ -82,15 +50,6 @@ public class StoredProcOutboundGateway extends AbstractReplyProducingMessageHand } - /** - * Verifies parameters, sets the parameters on {@link SimpleJdbcCallOperations} - * and ensures the appropriate {@link SqlParameterSourceFactory} is defined - * when {@link ProcedureParameter} are passed in. - */ - @Override - protected void doInit() { - }; - @Override protected Object handleRequestMessage(Message requestMessage) { @@ -123,136 +82,6 @@ public class StoredProcOutboundGateway extends AbstractReplyProducingMessageHand } - /** - * The name of the Stored Procedure or Stored Function to be executed. - * If {@link StoredProcExecutor#isFunction} is set to "true", then this - * property specifies the Stored Function name. - * - * Alternatively you can also specify the Stored Procedure name via - * {@link StoredProcExecutor#setStoredProcedureNameExpression(Expression)}. - * - * @param storedProcedureName Must not be null and must not be empty - * - * @see StoredProcExecutor#setStoredProcedureNameExpression(Expression) - * @see StoredProcExecutor#setStoredProcedureName(String) - * - * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} - * - */ - @Deprecated - public void setStoredProcedureName(String storedProcedureName) { - this.executor.setStoredProcedureName(storedProcedureName); - } - - /** - * Explicit declarations are necessary if the database you use is not a - * Spring-supported database. Currently Spring supports metadata lookup of - * stored procedure calls for the following databases: - * - *
    - *
  • Apache Derby
  • - *
  • DB2
  • - *
  • MySQL
  • - *
  • Microsoft SQL Server
  • - *
  • Oracle
  • - *
  • Sybase
  • - *
  • PostgreSQL
  • - *
- * , , - * We also support metadata lookup of stored functions for the following - * databases: - * - *
    - *
  • MySQL
  • - *
  • Microsoft SQL Server
  • - *
  • Oracle
  • - *
  • PostgreSQL
  • - *
- * - * See also: http://static.springsource.org/spring/docs/3.1.0.M2/spring-framework-reference/html/jdbc.html - * - * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} - * - * @see StoredProcExecutor#setSqlParameters(List) - */ - @Deprecated - public void setSqlParameters(List sqlParameters) { - this.executor.setSqlParameters(sqlParameters); - } - - /** - * Does your stored procedure return one or more result sets? If so, you - * can use the provided method for setting the respective RowMappers. - * - * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} - * - * @see StoredProcExecutor#setReturningResultSetRowMappers(Map) - */ - @Deprecated - public void setReturningResultSetRowMappers( - Map> returningResultSetRowMappers) { - this.executor.setReturningResultSetRowMappers(returningResultSetRowMappers); - } - - /** - * If true, the JDBC parameter definitions for the stored procedure are not - * automatically derived from the underlying JDBC connection. In that case - * you must pass in {@link SqlParameter} explicitly.. - * - * @param ignoreColumnMetaData Defaults to false. - * - * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} - * - * @see StoredProcExecutor#setIgnoreColumnMetaData(boolean) - */ - @Deprecated - public void setIgnoreColumnMetaData(boolean ignoreColumnMetaData) { - this.executor.setIgnoreColumnMetaData(ignoreColumnMetaData); - } - - /** - * Indicates the procedure's return value should be included in the results - * returned. - * - * @param returnValueRequired - * - * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} - * - * @see StoredProcExecutor#setReturnValueRequired(boolean) - */ - @Deprecated - public void setReturnValueRequired(boolean returnValueRequired) { - this.executor.setReturnValueRequired(returnValueRequired); - } - - /** - * Custom Stored Procedure parameters that may contain static values - * or Strings representing an {@link Expression}. - * - * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} - * - * @see StoredProcExecutor#setProcedureParameters(List) - */ - @Deprecated - public void setProcedureParameters(List procedureParameters) { - this.executor.setProcedureParameters(procedureParameters); - } - - /** - * Indicates whether a Stored Procedure or a Function is being executed. - * The default value is false. - * - * @param isFunction If set to true an Sql Function is executed rather than a Stored Procedure. - * - * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} - * - * @see StoredProcExecutor#setIsFunction(boolean) - */ - @Deprecated - public void setIsFunction(boolean isFunction) { - this.executor.setIsFunction(isFunction); - } - /** * This parameter indicates that only one result object shall be returned from * the Stored Procedure/Function Call. If set to true, a resultMap that contains @@ -277,73 +106,4 @@ public class StoredProcOutboundGateway extends AbstractReplyProducingMessageHand this.expectSingleResult = expectSingleResult; } - /** - * Provides the ability to set a custom {@link SqlParameterSourceFactory}. - * Keep in mind that if {@link ProcedureParameter} are set explicitly and - * you would like to provide a custom {@link SqlParameterSourceFactory}, - * then you must provide an instance of {@link ExpressionEvaluatingSqlParameterSourceFactory}. - * - * If not the SqlParameterSourceFactory will be replaced by the default - * {@link ExpressionEvaluatingSqlParameterSourceFactory}. - * - * @param sqlParameterSourceFactory - * - * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} - * - * @see StoredProcExecutor#setSqlParameterSourceFactory(SqlParameterSourceFactory) - */ - @Deprecated - public void setSqlParameterSourceFactory(SqlParameterSourceFactory sqlParameterSourceFactory) { - this.executor.setSqlParameterSourceFactory(sqlParameterSourceFactory); - } - - /** - * If set to 'true', the payload of the Message will be used as a source for - * providing parameters. If false the entire Message will be available as a - * source for parameters. - * - * If no {@link ProcedureParameter} are passed in, this property will default to - * 'true'. This means that using a default {@link BeanPropertySqlParameterSourceFactory} - * the bean properties of the payload will be used as a source for parameter values for - * the to-be-executed Stored Procedure or Function. - * - * However, if {@link ProcedureParameter} are passed in, then this property - * will by default evaluate to 'false'. {@link ProcedureParameter} allow for - * SpEl Expressions to be provided and therefore it is highly beneficial to - * have access to the entire {@link Message}. - * - * @param usePayloadAsParameterSource If false the entire {@link Message} is used as parameter source. - * - * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} - * - * @see StoredProcExecutor#setUsePayloadAsParameterSource(boolean) - */ - @Deprecated - public void setUsePayloadAsParameterSource(boolean usePayloadAsParameterSource) { - this.executor.setUsePayloadAsParameterSource(usePayloadAsParameterSource); - } - - /** - * If this variable is set to true then all results from a stored - * procedure call that don't have a corresponding {@link SqlOutParameter} - * declaration will be bypassed. - * - * E.g. Stored Procedures may return an update count value, even though your - * Stored Procedure only declared a single result parameter. The exact behavior - * depends on the used database. - * - * The value is set on the underlying {@link JdbcTemplate}. - * - * Only few developers will probably ever like to process update counts, thus - * the value defaults to true. - * - * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} - * - * @see StoredProcExecutor#setSkipUndeclaredResults(boolean) - */ - @Deprecated - public void setSkipUndeclaredResults(boolean skipUndeclaredResults) { - this.executor.setSkipUndeclaredResults(skipUndeclaredResults); - } - } diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcPollingChannelAdapter.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcPollingChannelAdapter.java index f274abbc4c..83460f0942 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcPollingChannelAdapter.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcPollingChannelAdapter.java @@ -16,23 +16,13 @@ package org.springframework.integration.jdbc; import java.sql.CallableStatement; -import java.util.List; import java.util.Map; -import javax.sql.DataSource; - -import org.springframework.expression.Expression; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessagingException; import org.springframework.integration.context.IntegrationObjectSupport; import org.springframework.integration.core.MessageSource; -import org.springframework.integration.jdbc.storedproc.ProcedureParameter; import org.springframework.integration.support.MessageBuilder; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.RowMapper; -import org.springframework.jdbc.core.SqlOutParameter; -import org.springframework.jdbc.core.SqlParameter; -import org.springframework.jdbc.core.simple.SimpleJdbcCall; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessagingException; import org.springframework.util.Assert; /** @@ -50,26 +40,6 @@ public class StoredProcPollingChannelAdapter extends IntegrationObjectSupport im private volatile boolean expectSingleResult = false; - /** - * Constructor taking {@link DataSource} from which the DB Connection can be - * obtained and the stored procedure name to execute. - * - * @param dataSource used to create a {@link SimpleJdbcCall} - * @param storedProcedureName Name of the Stored Procedure or Function to execute - * - * @deprecated Since 2.2 use the constructor that expects a {@link StoredProcExecutor} instead - */ - @Deprecated - public StoredProcPollingChannelAdapter(DataSource dataSource, String storedProcedureName) { - - Assert.notNull(dataSource, "dataSource must not be null."); - Assert.hasText(storedProcedureName, "storedProcedureName must not be null and cannot be empty."); - - this.executor = new StoredProcExecutor(dataSource); - this.executor.setStoredProcedureName(storedProcedureName); - - } - /** * Constructor taking {@link StoredProcExecutor}. * @@ -83,11 +53,6 @@ public class StoredProcPollingChannelAdapter extends IntegrationObjectSupport im } - @Override - protected void onInit() throws Exception { - super.onInit(); - } - /** * Executes the query. If a query result set contains one or more rows, the * Message payload will contain either a List of Maps for each row or, if a @@ -142,158 +107,11 @@ public class StoredProcPollingChannelAdapter extends IntegrationObjectSupport im return this.executor.executeStoredProcedure(); } + @Override public String getComponentType(){ return "stored-proc:inbound-channel-adapter"; } - /** - * The name of the Stored Procedure or Stored Function to be executed. - * If {@link StoredProcExecutor#isFunction} is set to "true", then this - * property specifies the Stored Function name. - * - * Alternatively you can also specify the Stored Procedure name via - * {@link StoredProcExecutor#setStoredProcedureNameExpression(Expression)}. - * - * @param storedProcedureName Must not be null and must not be empty - * - * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} - * - * @see StoredProcExecutor#setStoredProcedureName(String) - */ - @Deprecated - public void setStoredProcedureName(String storedProcedureName) { - this.executor.setStoredProcedureName(storedProcedureName); - } - - /** - * Provides the ability to set a custom {@link SqlParameterSourceFactory}. - * Keep in mind that if {@link ProcedureParameter} are set explicitly and - * you would like to provide a custom {@link SqlParameterSourceFactory}, - * then you must provide an instance of {@link ExpressionEvaluatingSqlParameterSourceFactory}. - * - * If not the SqlParameterSourceFactory will be replaced by the default - * {@link ExpressionEvaluatingSqlParameterSourceFactory}. - * - * @param sqlParameterSourceFactory - * - * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} - * - * @see StoredProcExecutor#setSqlParameterSourceFactory(SqlParameterSourceFactory) - */ - @Deprecated - public void setSqlParameterSourceFactory(SqlParameterSourceFactory sqlParameterSourceFactory) { - this.executor.setSqlParameterSourceFactory(sqlParameterSourceFactory); - } - - /** - * Explicit declarations are necessary if the database you use is not a - * Spring-supported database. Currently Spring supports metadata lookup of - * stored procedure calls for the following databases: - * - *
    - *
  • Apache Derby
  • - *
  • DB2
  • - *
  • MySQL
  • - *
  • Microsoft SQL Server
  • - *
  • Oracle
  • - *
  • Sybase
  • - *
  • PostgreSQL
  • - *
- * , , - * We also support metadata lookup of stored functions for the following - * databases: - * - *
    - *
  • MySQL
  • - *
  • Microsoft SQL Server
  • - *
  • Oracle
  • - *
  • PostgreSQL
  • - *
- * - * See also: http://static.springsource.org/spring/docs/3.1.0.M2/spring-framework-reference/html/jdbc.html - * - * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} - * - * @see StoredProcExecutor#setSqlParameters(List) - */ - @Deprecated - public void setSqlParameters(List sqlParameters) { - this.executor.setSqlParameters(sqlParameters); - } - - /** - * Does your stored procedure return one or more result sets? If so, you - * can use the provided method for setting the respective Rowmappers. - * - * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} - * - * @see StoredProcExecutor#setReturningResultSetRowMappers(Map) - */ - @Deprecated - public void setReturningResultSetRowMappers( - Map> returningResultSetRowMappers) { - this.executor.setReturningResultSetRowMappers(returningResultSetRowMappers); - } - - /** - * If true, the JDBC parameter definitions for the stored procedure are not - * automatically derived from the underlying JDBC connection. In that case - * you must pass in {@link SqlParameter} explicitly.. - * - * @param ignoreColumnMetaData Defaults to false. - * - * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} - * - * @see StoredProcExecutor#setIgnoreColumnMetaData(boolean) - */ - @Deprecated - public void setIgnoreColumnMetaData(boolean ignoreColumnMetaData) { - this.executor.setIgnoreColumnMetaData(ignoreColumnMetaData); - } - - /** - * Indicates the procedure's return value should be included in the results - * returned. - * - * @param returnValueRequired - * - * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} - * - * @see StoredProcExecutor#setReturnValueRequired(boolean) - */ - @Deprecated - public void setReturnValueRequired(boolean returnValueRequired) { - this.executor.setReturnValueRequired(returnValueRequired); - } - - /** - * Custom Stored Procedure parameters that may contain static values - * or Strings representing an {@link Expression}. - * - * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} - * - * @see StoredProcExecutor#setProcedureParameters(List) - */ - @Deprecated - public void setProcedureParameters(List procedureParameters) { - this.executor.setProcedureParameters(procedureParameters); - } - - /** - * Indicates whether a Stored Procedure or a Function is being executed. - * The default value is false. - * - * @param isFunction If set to true an Sql Function is executed rather than a Stored Procedure. - * - * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} - * - * @see StoredProcExecutor#setIsFunction(boolean) - */ - @Deprecated - public void setFunction(boolean isFunction) { - this.executor.setIsFunction(isFunction); - } - /** * This parameter indicates that only one result object shall be returned from * the Stored Procedure/Function Call. If set to true, a resultMap that contains @@ -318,28 +136,4 @@ public class StoredProcPollingChannelAdapter extends IntegrationObjectSupport im this.expectSingleResult = expectSingleResult; } - /** - * If this variable is set to true then all results from a stored - * procedure call that don't have a corresponding {@link SqlOutParameter} - * declaration will be bypassed. - * - * E.g. Stored Procedures may return an update count value, even though your - * Stored Procedure only declared a single result parameter. The exact behavior - * depends on the used database. - * - * The value is set on the underlying {@link JdbcTemplate}. - * - * Only few developers will probably ever like to process update counts, thus - * the value defaults to true. - * - * @deprecated Since 2.2 set the respective property on the passed-in {@link StoredProcExecutor} - * - * @see StoredProcExecutor#setSkipUndeclaredResults(boolean) - * - */ - @Deprecated - public void setSkipUndeclaredResults(boolean skipUndeclaredResults) { - this.executor.setSkipUndeclaredResults(skipUndeclaredResults); - } - } diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcPollingChannelAdapterWithSpringContextIntegrationTests-context.xml b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcPollingChannelAdapterWithSpringContextIntegrationTests-context.xml index 8947443461..505a320138 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcPollingChannelAdapterWithSpringContextIntegrationTests-context.xml +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcPollingChannelAdapterWithSpringContextIntegrationTests-context.xml @@ -23,7 +23,7 @@ - + diff --git a/spring-integration-redis/src/main/java/org/springframework/integration/redis/inbound/RedisQueueMessageDrivenEndpoint.java b/spring-integration-redis/src/main/java/org/springframework/integration/redis/inbound/RedisQueueMessageDrivenEndpoint.java index b54516d82f..415f89cf40 100644 --- a/spring-integration-redis/src/main/java/org/springframework/integration/redis/inbound/RedisQueueMessageDrivenEndpoint.java +++ b/spring-integration-redis/src/main/java/org/springframework/integration/redis/inbound/RedisQueueMessageDrivenEndpoint.java @@ -178,10 +178,15 @@ public class RedisQueueMessageDrivenEndpoint extends MessageProducerSupport impl value = this.boundListOperations.rightPop(this.receiveTimeout, TimeUnit.MILLISECONDS); } catch (Exception e) { - logger.error("Failed to execute listening task. Will attempt to resubmit in " + this.recoveryInterval + " milliseconds.", e); this.listening = false; - this.sleepBeforeRecoveryAttempt(); - this.publishException(e); + if (this.active) { + logger.error("Failed to execute listening task. Will attempt to resubmit in " + this.recoveryInterval + " milliseconds.", e); + this.publishException(e); + this.sleepBeforeRecoveryAttempt(); + } + else { + logger.debug("Failed to execute listening task. " + e.getClass() + ": " + e.getMessage()); + } return; } diff --git a/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XPathRouterParserTests.java b/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XPathRouterParserTests.java index 0320c60a83..3baf2206b6 100644 --- a/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XPathRouterParserTests.java +++ b/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XPathRouterParserTests.java @@ -267,6 +267,4 @@ public class XPathRouterParserTests { } } - public static class MyChannelResolver extends BeanFactoryChannelResolver{} - } diff --git a/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XPathRouterTests-context.xml b/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XPathRouterTests-context.xml index f49ebf4593..ec6a65ec22 100644 --- a/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XPathRouterTests-context.xml +++ b/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XPathRouterTests-context.xml @@ -8,34 +8,34 @@ http://www.springframework.org/schema/integration/xml http://www.springframework.org/schema/integration/xml/spring-integration-xml.xsd"> - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - + @@ -46,5 +46,4 @@ - diff --git a/spring-integration-xmpp/src/main/java/org/springframework/integration/xmpp/XmppHeaders.java b/spring-integration-xmpp/src/main/java/org/springframework/integration/xmpp/XmppHeaders.java index d9517de9a8..06713f3464 100644 --- a/spring-integration-xmpp/src/main/java/org/springframework/integration/xmpp/XmppHeaders.java +++ b/spring-integration-xmpp/src/main/java/org/springframework/integration/xmpp/XmppHeaders.java @@ -33,22 +33,10 @@ public class XmppHeaders { public static final String TO = PREFIX + "to"; - /** - * {@link Deprecated} use {@link #TO} instead - */ - @Deprecated - public static final String CHAT_TO = TO; - public static final String FROM = PREFIX + "from"; public static final String THREAD = PREFIX + "thread"; - /** - * {@link Deprecated} use {@link #THREAD} instead - */ - @Deprecated - public static final String CHAT_THREAD_ID = THREAD; - public static final String SUBJECT = PREFIX + "subject"; public static final String TYPE = PREFIX + "type"; diff --git a/spring-integration-xmpp/src/main/java/org/springframework/integration/xmpp/core/AbstractXmppConnectionAwareEndpoint.java b/spring-integration-xmpp/src/main/java/org/springframework/integration/xmpp/core/AbstractXmppConnectionAwareEndpoint.java index b210e6fff3..b4d20e37fa 100644 --- a/spring-integration-xmpp/src/main/java/org/springframework/integration/xmpp/core/AbstractXmppConnectionAwareEndpoint.java +++ b/spring-integration-xmpp/src/main/java/org/springframework/integration/xmpp/core/AbstractXmppConnectionAwareEndpoint.java @@ -19,7 +19,6 @@ package org.springframework.integration.xmpp.core; import org.jivesoftware.smack.XMPPConnection; import org.springframework.beans.factory.BeanFactory; -import org.springframework.messaging.MessageChannel; import org.springframework.integration.endpoint.MessageProducerSupport; import org.springframework.util.Assert; @@ -43,15 +42,6 @@ public abstract class AbstractXmppConnectionAwareEndpoint extends MessageProduce this.xmppConnection = xmppConnection; } - /** - * {@link Deprecated} This method will be eligible for removal in 2.1. - * Use {@link #setOutputChannel(MessageChannel)} instead. - */ - @Deprecated - public void setRequestChannel(MessageChannel requestChannel) { - this.setOutputChannel(requestChannel); - } - @Override protected void onInit() { super.onInit(); diff --git a/src/reference/docbook/amqp.xml b/src/reference/docbook/amqp.xml index 2fc36fbd91..a487da810e 100644 --- a/src/reference/docbook/amqp.xml +++ b/src/reference/docbook/amqp.xml @@ -282,7 +282,7 @@ this list can also be simple patterns to be matched against the header names (e. -
+
Outbound Channel Adapter A configuration sample for an AMQP Outbound Channel Adapter is shown @@ -378,7 +378,7 @@ this list can also be simple patterns to be matched against the header names (e.
-
+
Inbound Gateway A configuration sample for an AMQP Inbound Gateway is shown below. @@ -434,7 +434,7 @@ this list can also be simple patterns to be matched against the header names (e.
-
+
Outbound Gateway A configuration sample for an AMQP Outbound Gateway is shown below. diff --git a/src/reference/docbook/channel-adapter.xml b/src/reference/docbook/channel-adapter.xml index d8868b2267..b5a1383b75 100644 --- a/src/reference/docbook/channel-adapter.xml +++ b/src/reference/docbook/channel-adapter.xml @@ -84,7 +84,7 @@
- Configuring Outbound Channel Adapter + Configuring An Outbound Channel Adapter An "outbound-channel-adapter" element can also connect a MessageChannel to any POJO consumer method that should be invoked with the payload of Messages sent to that channel. diff --git a/src/reference/docbook/channel.xml b/src/reference/docbook/channel.xml index 0ee28aa35a..633b1e1beb 100644 --- a/src/reference/docbook/channel.xml +++ b/src/reference/docbook/channel.xml @@ -199,17 +199,27 @@ The DirectChannel internally delegates to a Message Dispatcher to invoke its - subscribed Message Handlers, and that dispatcher can have a load-balancing strategy. The load-balancer - determines how invocations will be ordered in the case that there are multiple handlers subscribed to the - same channel. When using the namespace support described below, the default strategy is - "round-robin" which essentially load-balances across the handlers in rotation. - - The "round-robin" strategy is currently the only implementation available out-of-the-box in Spring - Integration. Other strategy implementations may be added in future versions. - + subscribed Message Handlers, and that dispatcher can have a load-balancing strategy exposed via + load-balancer or load-balancer-ref attributes (mutually exclusive). The load balancing strategy + is used by the Message Dispatcher to help determine how Messages are distributed amongst Message Handlers + in the case that there are multiple Message Handlers subscribed to the same channel. + As a convinience the load-balancer attribute exposes enumeration of values pointing to pre-existing implementations + of LoadBalancingStrategy. + The "round-robin" (load-balances across the handlers in rotation) and "none" (for the cases where one wants to explicitely disable load balancing) + are the only available values. + Other strategy implementations may be added in future versions. + However, since version 3.0 you can provide your own implementation of the LoadBalancingStrategy and + inject it using load-balancer-ref attribute which should point to a bean that implements + LoadBalancingStrategy. + + + + +]]> + Note that load-balancer or load-balancer-ref attributes are mutually exclusive. - The load-balancer also works in combination with a boolean failover property. + The load-balancing also works in combination with a boolean failover property. If the "failover" value is true (the default), then the dispatcher will fall back to any subsequent handlers as necessary when preceding handlers throw Exceptions. The order is determined by an optional order value defined on the handlers themselves or, if no such value exists, the order in which the @@ -539,8 +549,8 @@ payload to an Integer. message-store attribute as shown in the next example. - - + + ]]> diff --git a/src/reference/docbook/endpoint-summary.xml b/src/reference/docbook/endpoint-summary.xml new file mode 100644 index 0000000000..6a5c9d7443 --- /dev/null +++ b/src/reference/docbook/endpoint-summary.xml @@ -0,0 +1,225 @@ + + + Endpoint Quick Reference Table + + As discussed in the sections above, Spring Integration provides a number of endpoints used + to interface with external systems, file systems etc. The following is a summary of the various + endpoints with quick links to the appropriate chapter. + + + To recap, Inbound Channel Adapters are used for one-way integration + bringing data into the messagng application. Outbound Channel Adapters + are used for one-way integration to send data out of the messaging application. + Inbound Gateways are used for a bidirectional integration flow where + some other system invokes the messaging application and receives a reply. + Outbound Gateways are used for a bidirectional integration flow where + the messaging application invokes some external service or entity, expecting a result. + + + + + + + + + + + Module + Inbound Adapter + Outbound Adapter + Inbound Gateway + Outbound Gateway + + + + + AMQP + + + + + + + Events + + + N + N + + + Feed + + N + N + N + + + File + and + + N + + + + FTP(S) + + + N + + + + Gemfire + and + + N + N + + + HTTP + + + + + + + JDBC + and + and + N + and + + + JMS + and + + + + + + JMX + and + and + + and + + N + + + + JPA + + + N + and + + + Mail + + + N + N + + + MongoDB + + + N + N + + + Redis + and + and + + and + and + + N + N + + + Resource + + N + N + N + + + RMI + N + N + + + + + SFTP + + + N + + + + Stream + + + N + N + + + Syslog + + N + N + N + + + TCP + + + + + + + Twitter + + + N + N + + + UDP + + + N + N + + + Web Services + N + N + + + + + XMPP + and + and + N + N + + + +
+ + In addition, as discussed in , endpoints are provided + for interfacing with Plain Old Java Objects + (POJOs). As discussed in , the <int:inbound-channel-adapter> + allows polling a java method for data; the + <int:outbound-channel-adapter> allows sending data to a void method, and + as discussed in , the <int:gateway> allows any Java program + to invoke a messaging flow. Each of these without requiring any source level + dependencies on Spring Integration. The equivalent of an outbound gateway in this context would be to use a + to invoke a method that returns an Object of some kind. + +
diff --git a/src/reference/docbook/feed.xml b/src/reference/docbook/feed.xml index cb02137b39..a2944a3a8b 100644 --- a/src/reference/docbook/feed.xml +++ b/src/reference/docbook/feed.xml @@ -62,55 +62,12 @@ xsi:schemaLocation="http://www.springframework.org/schema/integration/feed Spring Integration provides a convenient mechanism to eliminate the need to worry about duplicate entries. Each feed entry will have a published date field. Every time a new Message is generated and sent, Spring Integration will store the value of the latest published date in an instance of the - org.springframework.integration.metadata.MetadataStore strategy. The MetadataStore interface is - designed to store various types of generic meta-data (e.g., published date of the last feed entry that has been processed) - to help components such as this Feed adapter deal with duplicates. + MetadataStore strategy ().
- - The default rule for locating this metadata store is as follows: - Spring Integration will look for a bean of type - org.springframework.integration.metadata.MetadataStore in - the ApplicationContext. If one is found then it will be used, otherwise - it will create a new instance of SimpleMetadataStore - which is an in-memory implementation that will only persist metadata within - the lifecycle of the currently running Application Context. This means - that upon restart you may end up with duplicate entries. - - - If you need to persist metadata between Application Context restarts, two - persistent MetadataStores are available: - - - PropertiesPersistingMetadataStore - RedisMetadataStore - - - The PropertiesPersistingMetadataStore is backed by - a properties file and a - PropertiesPersister. - - ]]> - - As of Spring Integration 3.0 a Redis-based - MetadataStore is also available. For - more information regarding the RedisMetadataStore - see . - - - Be careful when using the same Redis instancce across multiple application - contexts as separate Feed adapters may accidentally use the same persisted - key. - - - Alternatively, you could provide your own implementation of the - MetadataStore interface (e.g. JdbcMetadataStore) - and configure it as bean in the Application Context. - - - The key used to persist the latest published date is the value of the (required) - id attribute of the Feed Inbound Channel Adapter component plus the feedUrl - from the adapter's configuration. - + + The key used to persist the latest published date is the value of the (required) + id attribute of the Feed Inbound Channel Adapter component plus the feedUrl + from the adapter's configuration. +
diff --git a/src/reference/docbook/file.xml b/src/reference/docbook/file.xml index 515d3f0a00..3c18d47378 100644 --- a/src/reference/docbook/file.xml +++ b/src/reference/docbook/file.xml @@ -39,9 +39,8 @@ The AcceptOnceFileListFilter stores its state in memory. If you wish the state to survive a system restart, consider using the FileSystemPersistentAcceptOnceFileListFilter instead. This filter stores - the accepted file names in a MetadataStore. The framework supplies - several store implementations (such as Redis), or you can provide your own. This filter matches on - the filename and modified time. + the accepted file names in a MetadataStore strategy (). + This filter matches on the filename and modified time. AcceptOnceFileListFilter stores its state in memory. If you wish the state to survive a system restart, consider using the FtpPersistentAcceptOnceFileListFilter instead. This filter stores - the accepted file names in a MetadataStore. The framework supplies - several store implementations (such as Redis), or you can provide your own. This filter matches on - the filename and the remote modified time. - + the accepted file names in an instance of the + MetadataStore strategy (). + This filter matches on the filename and the remote modified time. + Beginning with version 3.0, you can also specify a filter used to filter the files locally, once they have @@ -208,8 +208,8 @@ protected void postProcessClientBeforeConnect(T client) throws IOException { The AcceptOnceFileListFilter stores its state in memory. If you wish the state to survive a system restart, consider using the FileSystemPersistentAcceptOnceFileListFilter as a local filter instead. This filter stores - the accepted file names in a MetadataStore. The framework supplies - several store implementations (such as Redis), or you can provide your own. + the accepted file names in an instance of the + MetadataStore strategy (). This filter compares the filename and modified timestamp. If you wish to use this technique to avoid a re-synchronized file from being processed, you should use the preserve-timestamp attribute discussed above. diff --git a/src/reference/docbook/gemfire.xml b/src/reference/docbook/gemfire.xml index 6bcc648d4a..df9edb4100 100644 --- a/src/reference/docbook/gemfire.xml +++ b/src/reference/docbook/gemfire.xml @@ -28,7 +28,7 @@ xsi:schemaLocation="http://www.springframework.org/schema/integration/gemfire http://www.springframework.org/schema/integration/gemfire/spring-integration-gemfire.xsd"]]>
-
+
Inbound Channel Adapter The inbound-channel-adapter produces messages on a channel triggered by a GemFire EntryEvent. GemFire @@ -49,7 +49,7 @@ xsi:schemaLocation="http://www.springframework.org/schema/integration/gemfire If expression is not provided the message payload will be a GemFire EntryEvent
-
+
Continuous Query Inbound Channel Adapter The cq-inbound-channel-adapter produces messages a channel triggered by a GemFire continuous query or CqEvent event. Spring GemFire introduced @@ -90,7 +90,7 @@ xsi:schemaLocation="http://www.springframework.org/schema/integration/gemfire
-
+
Outbound Channel Adapter The outbound-channel-adapter writes cache entries mapped from the message payload. In its simplest form, it expects a diff --git a/src/reference/docbook/handler-advice.xml b/src/reference/docbook/handler-advice.xml index 8a7a25e383..3756066b2e 100644 --- a/src/reference/docbook/handler-advice.xml +++ b/src/reference/docbook/handler-advice.xml @@ -295,10 +295,11 @@ Caused by: java.lang.RuntimeException: foo Spring Retry has a great deal of flexibility for determining which exceptions can invoke retry. The default configuration will retry - for all exceptions. Given that, user exceptions may be wrapped in - a MessagingException in the underlying handler, - we need to ensure that the classification examines the exception causes. - The default classifier just looks at the top level exception. + for all exceptions and the exception classifier just looks at the + top level exception. If you configure it to, say, only retry + on BarException and your application throws + a FooException where the cause is a + BarException, retry will not occur. Since Spring Retry 1.0.3, the diff --git a/src/reference/docbook/index.xml b/src/reference/docbook/index.xml index 4f38687421..d1a7ba6bf2 100644 --- a/src/reference/docbook/index.xml +++ b/src/reference/docbook/index.xml @@ -115,12 +115,13 @@ - Integration Adapters + Integration Endpoints This section covers the various Channel Adapters and Messaging Gateways provided by Spring Integration to support Message-based communication with external systems. + @@ -128,7 +129,6 @@ - @@ -140,6 +140,7 @@ + diff --git a/src/reference/docbook/meta-data-store.xml b/src/reference/docbook/meta-data-store.xml new file mode 100644 index 0000000000..f242f3c0da --- /dev/null +++ b/src/reference/docbook/meta-data-store.xml @@ -0,0 +1,68 @@ + +
+ Metadata Store + + Many external systems, services or resources aren't transactional (Twitter, RSS, file system etc.) + and there is no any ability to mark the data as read. Or there is just need to implement the + Enterprise Integration Pattern Idempotent Receiver + in some integration solutions. To achieve this goal and store some previous state of the Endpoint before the next + interaction with external system, or deal with the next Message, Spring Integration provides the Metadata Store + component being an implementation of the org.springframework.integration.metadata.MetadataStore + interface with a general key-value contract. + + + The Metadata Store is designed to store various types of generic meta-data + (e.g., published date of the last feed entry that has been processed) to help components such as the Feed adapter deal with duplicates. + If a component is not directly provided with a reference to a MetadataStore, + the algorithm for locating a metadata store is as follows: First, look for a bean with id + metadataStore in the ApplicationContext. If one is found then it will be used, otherwise + it will create a new instance of SimpleMetadataStore which is an in-memory implementation + that will only persist metadata within the lifecycle of the currently running Application Context. This means + that upon restart you may end up with duplicate entries. + + + If you need to persist metadata between Application Context restarts, two + persistent MetadataStores are provided by the framework: + + + PropertiesPersistingMetadataStore + + + + The PropertiesPersistingMetadataStore is backed by a properties file and a + PropertiesPersister. + + ]]> + + Alternatively, you can provide your own implementation of the + MetadataStore interface (e.g. JdbcMetadataStore) + and configure it as a bean in the Application Context. + +
+ Idempotent Receiver + + The Metadata Store is useful for implementating the + EIP Idempotent Receiver pattern, when + there is need to filter an incoming Message if it has already been processed, and just discard + it or perform some other logic on discarding. The following configuration is an example of how to do this: + + + + + + + +]]> + + The value of the idempotent entry may be some expiration date, after which that entry should + be removed from Metadata Store by some scheduled reaper. + +
+ +
diff --git a/src/reference/docbook/redis.xml b/src/reference/docbook/redis.xml index e3c71c2be7..4fa5ea345c 100644 --- a/src/reference/docbook/redis.xml +++ b/src/reference/docbook/redis.xml @@ -424,15 +424,18 @@ rt.setConnectionFactory(redisConnectionFactory);]]> Redis Metadata Store As of Spring Integration 3.0 a new Redis-based - MetadataStore - implementation is available. The RedisMetadataStore can + MetadataStore + () implementation is available. The RedisMetadataStore can be used to maintain state of a MetadataStore across application restarts. This new MetadataStore implementation can be used with adapters such as: - Twitter Inbound Adapters - Feed Inbound Channel Adapter + + + + + In order to instruct these adapters to use the new RedisMetadataStore @@ -444,11 +447,16 @@ rt.setConnectionFactory(redisConnectionFactory);]]> ]]> - - Be careful when using the same Redis instancce across multiple application - contexts as separate adapters may accidentally use the same persisted - key. - + + The RedisMetadataStore is backed by + RedisProperties and interaction with it uses + BoundHashOperations, which, in turn, requires a key for the entire + Properties store. In the case of the MetadataStore, this + key plays the role of a region, which is useful in distributed environment, + when several applications use the same Redis server. By default this key has the value MetaData. +
RedisStore Inbound Channel Adapter diff --git a/src/reference/docbook/sftp.xml b/src/reference/docbook/sftp.xml index 7952a3d15e..63fc8aa1d5 100644 --- a/src/reference/docbook/sftp.xml +++ b/src/reference/docbook/sftp.xml @@ -317,10 +317,10 @@ xsi:schemaLocation="http://www.springframework.org/schema/integration/sftp The AcceptOnceFileListFilter stores its state in memory. If you wish the state to survive a system restart, consider using the SftpPersistentAcceptOnceFileListFilter instead. This filter stores - the accepted file names in a MetadataStore. The framework supplies - several store implementations (such as Redis), or you can provide your own. This filter matches on - the filename and the remote modified time. - + the accepted file names in an instance of the + MetadataStore strategy (). + This filter matches on the filename and the remote modified time. + Beginning with version 3.0, you can also specify a filter used to filter the files locally, once they have @@ -333,8 +333,8 @@ xsi:schemaLocation="http://www.springframework.org/schema/integration/sftp The AcceptOnceFileListFilter stores its state in memory. If you wish the state to survive a system restart, consider using the FileSystemPersistentAcceptOnceFileListFilter as a local filter instead. This filter stores - the accepted file names in a MetadataStore. The framework supplies - several store implementations (such as Redis), or you can provide your own. + the accepted file names in an instance of the + MetadataStore strategy (). This filter compares the filename and modified timestamp. If you wish to use this technique to avoid a re-synchronized file from being processed, you should use the preserve-timestamp attribute discussed above. diff --git a/src/reference/docbook/system-management.xml b/src/reference/docbook/system-management.xml index dacb6a1ea6..5cda05805b 100644 --- a/src/reference/docbook/system-management.xml +++ b/src/reference/docbook/system-management.xml @@ -3,10 +3,11 @@ xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xlink="http://www.w3.org/1999/xlink"> System Management - + + diff --git a/src/reference/docbook/twitter.xml b/src/reference/docbook/twitter.xml index f99e602207..0555ce44e5 100644 --- a/src/reference/docbook/twitter.xml +++ b/src/reference/docbook/twitter.xml @@ -148,34 +148,8 @@ twitter.oauth.accessTokenSecret=AbRxUAvyNCtqQtxFK8w5ZMtMj20KFhB6o]]>org.springframework.integration.metadata.MetadataStore which is a - strategy interface designed for storing various types of metadata (e.g., last retrieved tweet in this case). That strategy helps components such as - these Twitter adapters avoid duplicates. By default, Spring Integration will look for a bean of type - org.springframework.integration.metadata.MetadataStore in the ApplicationContext. Alternatively, - you can configure an explicit MetadataStore on the adapter. - If there is no explicit or default store, the adapter will create a new instance of SimpleMetadataStore - which is a simple in-memory implementation that will only persist metadata within the lifecycle of the currently running application context. - That means upon restart you may end up with duplicate entries. If you need to persist metadata between Application Context - restarts, you may use the PropertiesPersistingMetadataStore (which is backed by a properties file, and a persister - strategy), or you may create your own custom implementation of the MetadataStore interface (e.g., JdbcMetadatStore) - and configure it as a bean named 'metadataStore' within the Application Context. - - - As of Spring Integration 3.0 a Redis-based - MetadataStore is available. The - RedisMetadataStore allows you to maintain persisted - metadata across Application Context restarts. For more information see . - - - Be careful when using the same Redis instance across multiple application - contexts as separate Twitter adapters may accidentally use the same persisted - key. - - -]]> - - If the MetadataStore is persistent, during initialization, any Inbound Twitter Adapter (see below) - will retrieve the latest tweet id that has already been sent by the adapter. + The latest Tweet id will be stored in an instance of the org.springframework.integration.metadata.MetadataStore + strategy (e.g. last retrieved tweet in this case). For more information see . The key used to persist the latest twitter id is the value of the (required) @@ -232,7 +206,7 @@ twitter.oauth.accessTokenSecret=AbRxUAvyNCtqQtxFK8w5ZMtMj20KFhB6o]]> - Here is a link that will help you learn more about Twitter queries: http://search.twitter.com/operators + Refer to to learn more about Twitter queries.
diff --git a/src/reference/docbook/whats-new.xml b/src/reference/docbook/whats-new.xml index fac46686a3..4db5c8ddf5 100644 --- a/src/reference/docbook/whats-new.xml +++ b/src/reference/docbook/whats-new.xml @@ -5,104 +5,25 @@ What's new in Spring Integration 3.0? This chapter provides an overview of the new features and improvements - that have been introduced with Spring Integration 3.0 If you are interested - in even more detail, please take a look at the Issue Tracker tickets that + that have been introduced with Spring Integration 3.0. If you are interested + in more details, please see the Issue Tracker tickets that were resolved as part of the 3.0 development process.
New Components -
- TCP/IP Connection Events and Connection Management +
+ HTTP Request Mapping - The (supplied) TcpConnections now emit - ApplicationEvents (specifically - TcpConnectionEvents) when connections are - opened, closed, or an exception occurs. This allows applications - to be informed of changes to TCP connections using the normal - Spring ApplicationListener - mechanism. - - - AbstractTcpConnection has been renamed - TcpConnectionSupport; custom connections that - are subclasses of this class, can use its methods to publish events. - Similarly, AbstractTcpConnectionInterceptor has - been renamed to TcpConnectionInterceptorSupport. - - - In addition, a new <int-ip:tcp-connection-event-inbound-channel-adapter/> - is provided; by default, this adapter sends all TcpConnectionEvents - to a Channel. - - - Further, the TCP Connection Factories, now provide a new method - getOpenConnectionIds(), which returns a list of identifiers for all - open connections; this allows applications, for example, to broadcast to all - open connections. - - - Finally, the connection factories also provide a new method - closeConnection(String connectionId) which allows applications - to explicitly close a connection using its ID. - - - For more information see . - -
-
- Syslog Support - - Building on the 2.2 SyslogToMapTransformer Spring - Integration 3.0 now introduces - UDP and TCP inbound channel adapters especially tailored - for receiving SYSLOG messages. For more information, see - . - -
-
- JMX Support - - - - A new <int-jmx:tree-polling-channel-adapter/> is provided; this - adapter queries the JMX MBean tree and sends a message with a payload that is the - graph of objects that matches the query. By default the MBeans are mapped to - primitives and simple Objects like Map, List and arrays - permitting simple - transformation, for example, to JSON. - - - The IntegrationMBeanExporter now allows the configuration of - a custom ObjectNamingStrategy using the naming-strategy - attribute. - - - - - For more information, see . - -
-
- 'Tail' Support - - File 'tail'ing inbound channel adapters are now provided to generate messages when - lines are added to the end of text files; see . - -
-
- Inbound Channel Adapter Script Support - - The <int:inbound-channel-adapter/> now supports <expression/> - and <script/> sub-elements to create a - MessageSource; see . - -
-
- Content Enricher: Headers Enrichment Support - - The Content Enricher now provides configuration for <header/> - sub-elements, to enrich the outbound Message with headers based on the reply Message from the underlying - message flow. For more information see . + The HTTP module now provides powerful Request Mapping support for Inbound Endpoints. Class UriPathHandlerMapping + was replaced by IntegrationRequestMappingHandlerMapping, which is registered under the bean name + integrationRequestMappingHandlerMapping in the application context. Upon parsing of the HTTP Inbound Endpoint, + a new IntegrationRequestMappingHandlerMapping bean is either registered or an existing bean is being reused. + To achieve flexible Request Mapping configuration, Spring Integration provides the <request-mapping/> + sub-element for the <http:inbound-channel-adapter/> and the <http:inbound-gateway/>. + Both HTTP Inbound Endpoints are now fully based on the Request Mapping infrastructure that was introduced with Spring MVC 3.1. + For example, multiple paths are supported on a single inbound endpoint. + For more information see .
@@ -131,20 +52,6 @@ For more information see .
-
- HTTP Request Mapping - - The HTTP module now provides powerful Request Mapping support for Inbound Endpoints. Class UriPathHandlerMapping - was replaced by IntegrationRequestMappingHandlerMapping, which is registered under the bean name - integrationRequestMappingHandlerMapping in the application context. Upon parsing of the HTTP Inbound Endpoint, - a new IntegrationRequestMappingHandlerMapping bean is either registered or an existing bean is being reused. - To achieve flexible Request Mapping configuration, Spring Integration provides the <request-mapping/> - sub-element for <http:inbound-channel-adapter/> and <http:inbound-gateway/>. - Both HTTP Inbound Endpoints are now fully based on the Request Mapping infrastructure that was introduced with Spring MVC 3.1. - For example, multiple paths are supported on a single inbound endpoint. - For more information see . - -
Redis: New Components @@ -191,11 +98,113 @@ See for more information.
+
+ Syslog Support + + Building on the 2.2 SyslogToMapTransformer Spring + Integration 3.0 now introduces + UDP and TCP inbound channel adapters especially tailored + for receiving SYSLOG messages. For more information, see + . + +
+
+ 'Tail' Support + + File 'tail'ing inbound channel adapters are now provided to generate messages when + lines are added to the end of text files; see . + +
+
+ JMX Support + + + + A new <int-jmx:tree-polling-channel-adapter/> is provided; this + adapter queries the JMX MBean tree and sends a message with a payload that is the + graph of objects that matches the query. By default the MBeans are mapped to + primitives and simple Objects like Map, List and arrays - permitting simple + transformation, for example, to JSON. + + + The IntegrationMBeanExporter now allows the configuration of + a custom ObjectNamingStrategy using the naming-strategy + attribute. + + + + + For more information, see . + +
+
+ TCP/IP Connection Events and Connection Management + + TcpConnections now emit + ApplicationEvents (specifically + TcpConnectionEvents) when connections are + opened, closed, or an exception occurs. This allows applications + to be informed of changes to TCP connections using the normal + Spring ApplicationListener + mechanism. + + + AbstractTcpConnection has been renamed + TcpConnectionSupport; custom connections that + are subclasses of this class, can use its methods to publish events. + Similarly, AbstractTcpConnectionInterceptor has + been renamed to TcpConnectionInterceptorSupport. + + + In addition, a new <int-ip:tcp-connection-event-inbound-channel-adapter/> + is provided; by default, this adapter sends all TcpConnectionEvents + to a Channel. + + + Further, the TCP Connection Factories, now provide a new method + getOpenConnectionIds(), which returns a list of identifiers for all + open connections; this allows applications, for example, to broadcast to all + open connections. + + + Finally, the connection factories also provide a new method + closeConnection(String connectionId) which allows applications + to explicitly close a connection using its ID. + + + For more information see . + +
+
+ Inbound Channel Adapter Script Support + + The <int:inbound-channel-adapter/> now supports <expression/> + and <script/> sub-elements to create a + MessageSource; see . + +
+
+ Content Enricher: Headers Enrichment Support + + The Content Enricher now provides configuration for <header/> + sub-elements, to enrich the outbound Message with headers based on the reply Message from the underlying + message flow. For more information see . + +
General Changes - +
+ Message ID Generation + + Previously, message ids were generated using the JDK UUID.randomUUID() method. With this + release, the default mechanism has been changed to use a more efficient algorithm which + is significantly faster. In addition, the ability to change + the strategy used to generate message ids has been added. + For more information see . + +
<gateway> Changes @@ -208,204 +217,16 @@ It is now possible to entirely customize the way that gateway method calls are mapped to messages. + + The GatewayMethodMetadata is now public class and it makes possible flexibly + to configure the GatewayProxyFactoryBean programmatically from Java code. + For more information see .
-
- Aggregator 'empty-group-min-timeout' property - AbstractCorrelatingMessageHandler provides a new property - empty-group-min-timeout - to allow empty group expiry to run on a longer schedule than expiring partial groups. Empty groups will - not be removed from the MessageStore until they have not been modified - for at least this number of milliseconds. For more information see . - -
-
- Advising Filters - - Previously, when a <filter/> had a <request-handler-advice-chain/>, the discard - action was all performed within the scope of the advice chain (including any downstream flow - on the discard-channel). The filter element now has an attribute - discard-within-advice (default true), to allow the discard action to - be performed after the advice chain completes. See . - -
-
- Advising Endpoints using Annotations - - Request Handler Advice Chains can now be configured using annotations. See - . - -
-
- ObjectToStringTransformer Improvements - - This transformer now correctly transforms byte[] and char[] - payloads to String. For more information see . - -
-
- Web Service Outbound URI Configuration - - Web Service Outbound Gateway 'uri' attribute now supports <uri-variable/> substitution for all - URI-schemes supported by Spring Web Services. For more information see . - -
-
- FTP, SFTP and FTPS Cached Sessions - - The FTP, SFTP and FTPS endpoints no longer cache sessions by default. - - - The deprecated cached-sessions attribute has been removed from all endpoints. - Previously, the embedded caching mechanism controlled by this attribute's value didn't - provide a way to limit the size of the cache, which could - grow indefinitely. The CachingConnectionFactory was introduced in - release 2.1 and it became the preferred (and is now the only) way to cache sessions. - For more information, see - and . - - - The CachingConnectionFactory now provides a new method - resetCache(). This immediately closes idle sessions and causes in-use - sessions to be closed as and when they are returned to the cache. - - - The DefaultSftpSessionFactory (in conjunction with a - CachingSessionFactory) now supports multiplexing channels over - a single SSH connection (SFTP Only). - -
-
- FTP, SFTP and FTPS Inbound Adapters - - Previously, there was no way to override the default filter used to process files retrieved - from a remote server. The filter attribute determines which files are retrieved - but the FileReadingMessageSource uses an - AcceptOnceFileListFilter. This means that if a new copy of a file - is retrieved, with the same name as a previously copied file, no message was sent from the - adapter. - - - With this release, a new attribute local-filter allows you to override the - default filter, for example with an AcceptAllFileListFilter, or some - other custom filter. - - - For users that wish the behavior of the AcceptOnceFileListFilter - to be maintained across JVM executions, a custom filter that retains state, perhaps on - the file system, can now be configured. - - - Inbound Channel Adapters now support the preserve-timestamp attribute, which - sets the local file modified timestamp to the timestamp from the server (default false). - - - For more information, see - and . - -
-
- FTP, SFTP and FTPS Gateways - - - - The gateways now support the mv command, enabling - the renaming of remote files. - - - The gateways now support recursive ls and - mget commands, enabling - the retrieval of a remote file tree. - - - The gateways now support put and - mput commands, enabling - sending file(s) to the remote server. - - - The local-filename-generator-expression attribute is now supported, - enabling the naming of local files during retrieval. By default, the same - name as the remote file is used. - - - The local-directory-expression attribute is now supported, - enabling the naming of local directories during retrieval based on the remote directory. - - - - - For more information, see and . - -
-
- Remote File Template - - A new higher-level abstraction (RemoteFileTemplate) is provided over the - Session implementations used by the FTP and SFTP modules. While it is - used internally by endpoints, this abstraction can also be used programmatically and, like all - Spring *Template implemenations, reliably closes the underlying session while allowing - low level access to the session when needed. - - - For more information, see - and . - -
-
- JDBC Message Store Improvements - - Spring Integration 3.0 adds a new set of DDL - scripts for MySQL version 5.6.4 and higher. - Now MySQL supports fractional - seconds and is thus improving the FIFO ordering when - polling from a MySQL-based Message Store. For more information, - please see . - -
-
- JPA Support: Improvements - - Payloads to persist or - merge can now be of type - java.lang.Iterable. - - - In that case, each object returned by the - Iterable is treated as - an entity and persisted or merged using the underlying - EntityManager. - NULL values returned by the iterator are ignored. - - - The JPA adapters now have additional attributes to optionally 'flush' and 'clear' - entities from the associated persistence context after performing persistence operations. - - For more information see . -
-
- Jackson Support (JSON) - - - - A new abstraction for JSON conversion has been introduced. Implementations for Jackson 1.x - and Jackson 2 are currently provided, with the version being determined by presence on - the classpath. Previously, only Jackson 1.x was supported. - - - The ObjectToJsonTransformer and JsonToObjectTransformer - now emit/consume headers containing type information. - - - - - For more information, see 'JSON Transformers' in . - -
HTTP Endpoint Changes @@ -450,22 +271,23 @@ For more information see .
-
- AMQP Outbound Gateway Header Mapping +
+ Jackson Support (JSON) - Previously, the <int-amqp:outbound-gateway/> mapped headers before invoking the message - converter, and the converter could overwrite headers such as content-type. The - outbound adapter maps the headers after the conversion, which means headers like - content-type from the outbound Message (if present) are used. + + + A new abstraction for JSON conversion has been introduced. Implementations for Jackson 1.x + and Jackson 2 are currently provided, with the version being determined by presence on + the classpath. Previously, only Jackson 1.x was supported. + + + The ObjectToJsonTransformer and JsonToObjectTransformer + now emit/consume headers containing type information. + + - Starting with this release, the gateway now maps the headers after the message conversion, - consistent with the adapter. If your application relies on the previous behavior (where the - converter's headers overrode the mapped headers), you either need to filter those headers - (before the message reaches the gateway) - or set them appropriately. The headers affected by the SimpleMessageConverter - are content-type and content-encoding. Custom message converters - may set other headers. + For more information, see 'JSON Transformers' in .
@@ -479,85 +301,145 @@ For more information see .
-
- JMS Message Driven Channel Adapter +
+ Aggregator 'empty-group-min-timeout' property - Previously, when configuring a <message-driven-channel-adapter/>, if you wished to - use a specific TaskExecutor, it was necessary to declare a container - bean and provide it to the adapter using the container attribute. The - task-executor is now provided, allowing it to be set directly on the adapter. This is - in addition to several other container attributes that were already available. + The AbstractCorrelatingMessageHandler provides a new property + empty-group-min-timeout + to allow empty group expiry to run on a longer schedule than expiring partial groups. Empty groups will + not be removed from the MessageStore until they have not been modified + for at least this number of milliseconds. For more information see .
-
- RMI Inbound Gateway +
+ Persistent File List Filters (file, (S)FTP) - The RMI Inbound Gateway now supports an error-channel attribute. See - . + New FileListFilters that use a persistent MetadataStore are + now available. These can be used to prevent duplicate files after a system restart. See + , , and for more information.
-
- Stored Procedure Components Improvements +
+ Scripting Support: Variables Changes - For more complex database-specific types, not supported by the standard - CallableStatement.getObject method, 2 new additional - attributes were introduced to the <sql-parameter-definition/> - element with OUT-direction: - - - type-name - return-type - - - - The row-mapper attribute of the Stored Procedure Inbound Channel Adapter - <returning-resultset/> sub-element - now supports a reference to a RowMapper bean - definition. Previously, it contained just a class name (which is still supported). - - - For more information see . - + A new variables attribute has been introduced for scripting components. + In addition, variable bindings are now allowed for inline scripts. + See and for more information.
-
- IMAP Idle Connection Exceptions +
+ Direct Channel Load Balancing configuration - Previously, if an IMAP idle connection failed, it was logged but there was no mechanism to - inform an application. Such exceptions now generate ApplicationEvents. - Applications can obtain these events using an <int-event:inbound-channel-adapter> - or any ApplicationListener configured to receive an - ImapIdleExceptionEvent or one of its super classes. + Previously, when configuring LoadBalancingStrategy on the channel's 'dispatcher' sub-element, + the only available option was to use a pre-defined enumeration of values which did not allow one to set a custom implementation + of the LoadBalancingStrategy. You can now use load-balancer-ref to provide + a reference to a custom implementation of the LoadBalancingStrategy. + For more information see .
-
- Message ID Generation +
+ PublishSubscribeChannel Behavior - Previously, message ids were generated using the JDK UUID.randomUUID() method. With this - release, the default mechanism has been changed to use a more efficient algorithm which - is significantly faster. In addition, the ability to change - the strategy used to generate message ids has been added. - For more information see . + Previously, sending to a <publish-subscribe-channel/> that had + no subscribers would return a false result. If used in conjunction with + a MessagingTemplate, this would result in an exception being thrown. + Now, the PublishSubscribeChannel has a property + minSubscribers (default 0). If the message is sent to at least the minimum + number of subscribers, the send is deemed to be successful (even if zero). If an application + is expecting to get an exception under these conditions, set the minimum subscribers to at + least 1.
-
- XsltPayloadTransformer +
+ FTP, SFTP and FTPS Changes - You can now specify the transformer factory class name using the - transformer-factory-class attribute. See + The FTP, SFTP and FTPS endpoints no longer cache sessions by default -
-
- Message Headers and TCP - The TCP connection factories now enable the configuration of a flexible mechanism to - transfer selected headers (as well as the payload) over TCP. A new - TcpMessageMapper - enables the selection of the headers, and an appropriate (de)serializer needs to be - configured to write the resulting Map to the - TCP stream. A MapJsonSerializer is provided as a convenient - mechanism to transfer headers and payload over TCP. - For more information see . + The deprecated cached-sessions attribute has been removed from all endpoints. + Previously, the embedded caching mechanism controlled by this attribute's value didn't + provide a way to limit the size of the cache, which could + grow indefinitely. The CachingConnectionFactory was introduced in + release 2.1 and it became the preferred (and is now the only) way to cache sessions. + + + The CachingConnectionFactory now provides a new method + resetCache(). This immediately closes idle sessions and causes in-use + sessions to be closed as and when they are returned to the cache. + + + The DefaultSftpSessionFactory (in conjunction with a + CachingSessionFactory) now supports multiplexing channels over + a single SSH connection (SFTP Only). + + + FTP, SFTP and FTPS Inbound Adapters + + + Previously, there was no way to override the default filter used to process files retrieved + from a remote server. The filter attribute determines which files are retrieved + but the FileReadingMessageSource uses an + AcceptOnceFileListFilter. This means that if a new copy of a file + is retrieved, with the same name as a previously copied file, no message was sent from the + adapter. + + + With this release, a new attribute local-filter allows you to override the + default filter, for example with an AcceptAllFileListFilter, or some + other custom filter. + + + For users that wish the behavior of the AcceptOnceFileListFilter + to be maintained across JVM executions, a custom filter that retains state, perhaps on + the file system, can now be configured. + + + Inbound Channel Adapters now support the preserve-timestamp attribute, which + sets the local file modified timestamp to the timestamp from the server (default false). + + + FTP, SFTP and FTPS Gateways + + + + + The gateways now support the mv command, enabling + the renaming of remote files. + + + The gateways now support recursive ls and + mget commands, enabling + the retrieval of a remote file tree. + + + The gateways now support put and + mput commands, enabling + sending file(s) to the remote server. + + + The local-filename-generator-expression attribute is now supported, + enabling the naming of local files during retrieval. By default, the same + name as the remote file is used. + + + The local-directory-expression attribute is now supported, + enabling the naming of local directories during retrieval based on the remote directory. + + + + + Remote File Template + + + A new higher-level abstraction (RemoteFileTemplate) is provided over the + Session implementations used by the FTP and SFTP modules. While it is + used internally by endpoints, this abstraction can also be used programmatically and, like all + Spring *Template implementations, reliably closes the underlying session while allowing + low level access to the session when needed. + + + For more information, see + and .
@@ -593,54 +475,53 @@ set requires-reply to false.
-
- Delayer: delay expression +
+ AMQP Outbound Gateway Header Mapping - Previously, the <delayer> provided a delay-header-name attribute - to determine the delay value at runtime. In complex cases it was necessary - to precede the <delayer> with a <header-enricher>. - Spring Integration 3.0 introduced the expression attribute and expression - sub-element for dynamic delay determination. The delay-header-name attribute is now deprecated - because the header evaluation can be specified in the expression. In addition, - the ignore-expression-failures was introduced to control the behavior when an - expression evaluation fails. - For more information see . + Previously, the <int-amqp:outbound-gateway/> mapped headers before invoking the message + converter, and the converter could overwrite headers such as content-type. The + outbound adapter maps the headers after the conversion, which means headers like + content-type from the outbound Message (if present) are used. + + + Starting with this release, the gateway now maps the headers after the message conversion, + consistent with the adapter. If your application relies on the previous behavior (where the + converter's headers overrode the mapped headers), you either need to filter those headers + (before the message reaches the gateway) + or set them appropriately. The headers affected by the SimpleMessageConverter + are content-type and content-encoding. Custom message converters + may set other headers.
-
- PublishSubscribeChannel Behavior +
+ Stored Procedure Components Improvements - Previously, sending to a <publish-subscribe-channel/> that had - no subscribers would return a false result. If used in conjunction with - a MessagingTemplate, this would result in an exception being thrown. - Now, the PublishSubscribeChannel has a property - minSubscribers (default 0). If the message is sent to at least the minimum - number of subscribers, the send is deemed to be successful (even if zero). If an application - is expecting to get an exception under these conditions, set the minimum subscribers to at - least 1. + For more complex database-specific types, not supported by the standard + CallableStatement.getObject method, 2 new additional + attributes were introduced to the <sql-parameter-definition/> + element with OUT-direction: + + + type-name + return-type + + + + The row-mapper attribute of the Stored Procedure Inbound Channel Adapter + <returning-resultset/> sub-element + now supports a reference to a RowMapper bean + definition. Previously, it contained just a class name (which is still supported). + + + For more information see . +
-
- JPA Adapters: first-result attribute +
+ Web Service Outbound URI Configuration - Retrieving gateways had no mechanism to specify the first record to be retrieved which - is a common use case. The retrieving gateways now support specifying this parameter - using a first-result and first-result-expression attributes - to the gateway definition. . - -
-
- JPA Adapters: max-results and max-results-expression Attributes - - The JPA retrieving gateway and inbound adapter now have an attribute to specify the maximum - number of results in a result set as an expression. In addition, the - max-results attribute has been introduced to replace - max-number-of-results, which has been deprecated. - max-results and max-results-expression - are used to provide the maximum number of results, - or an expression to compute the maximum number of results, respectively, in the - result set. - For more information see . + Web Service Outbound Gateway 'uri' attribute now supports <uri-variable/> substitution for all + URI-schemes supported by Spring Web Services. For more information see .
@@ -665,20 +546,137 @@ For more information, see .
-
- Persistent File List Filters (file, (S)FTP) +
+ Advising Filters - New FileListFilters that use a persistent MetadataStore are - now available. These can be used to prevent duplicate files after a system restart. See - , , and for more information. + Previously, when a <filter/> had a <request-handler-advice-chain/>, the discard + action was all performed within the scope of the advice chain (including any downstream flow + on the discard-channel). The filter element now has an attribute + discard-within-advice (default true), to allow the discard action to + be performed after the advice chain completes. See .
-
- Scripting Support: Variables Changes +
+ Advising Endpoints using Annotations - A new variables attribute has been introduced for scripting components. - In addition, variable bindings are now allowed for inline scripts. - See and for more information. + Request Handler Advice Chains can now be configured using annotations. See + . + +
+
+ ObjectToStringTransformer Improvements + + This transformer now correctly transforms byte[] and char[] + payloads to String. For more information see . + +
+
+ JPA Support Changes + + Payloads to persist or + merge can now be of type + java.lang.Iterable. + + + In that case, each object returned by the + Iterable is treated as + an entity and persisted or merged using the underlying + EntityManager. + NULL values returned by the iterator are ignored. + + + The JPA adapters now have additional attributes to optionally 'flush' and 'clear' + entities from the associated persistence context after performing persistence operations. + + + Retrieving gateways had no mechanism to specify the first record to be retrieved which + is a common use case. The retrieving gateways now support specifying this parameter + using a first-result and first-result-expression attributes + to the gateway definition. . + + + The JPA retrieving gateway and inbound adapter now have an attribute to specify the maximum + number of results in a result set as an expression. In addition, the + max-results attribute has been introduced to replace + max-number-of-results, which has been deprecated. + max-results and max-results-expression + are used to provide the maximum number of results, + or an expression to compute the maximum number of results, respectively, in the + result set. + + For more information see . +
+
+ Delayer: delay expression + + Previously, the <delayer> provided a delay-header-name attribute + to determine the delay value at runtime. In complex cases it was necessary + to precede the <delayer> with a <header-enricher>. + Spring Integration 3.0 introduced the expression attribute and expression + sub-element for dynamic delay determination. The delay-header-name attribute is now deprecated + because the header evaluation can be specified in the expression. In addition, + the ignore-expression-failures was introduced to control the behavior when an + expression evaluation fails. + For more information see . + +
+
+ JDBC Message Store Improvements + + Spring Integration 3.0 adds a new set of DDL + scripts for MySQL version 5.6.4 and higher. + Now MySQL supports fractional + seconds and is thus improving the FIFO ordering when + polling from a MySQL-based Message Store. For more information, + please see . + +
+
+ IMAP Idle Connection Exceptions + + Previously, if an IMAP idle connection failed, it was logged but there was no mechanism to + inform an application. Such exceptions now generate ApplicationEvents. + Applications can obtain these events using an <int-event:inbound-channel-adapter> + or any ApplicationListener configured to receive an + ImapIdleExceptionEvent or one of its super classes. + +
+
+ Message Headers and TCP + + The TCP connection factories now enable the configuration of a flexible mechanism to + transfer selected headers (as well as the payload) over TCP. A new + TcpMessageMapper + enables the selection of the headers, and an appropriate (de)serializer needs to be + configured to write the resulting Map to the + TCP stream. A MapJsonSerializer is provided as a convenient + mechanism to transfer headers and payload over TCP. + For more information see . + +
+
+ JMS Message Driven Channel Adapter + + Previously, when configuring a <message-driven-channel-adapter/>, if you wished to + use a specific TaskExecutor, it was necessary to declare a container + bean and provide it to the adapter using the container attribute. The + task-executor is now provided, allowing it to be set directly on the adapter. This is + in addition to several other container attributes that were already available. + +
+
+ RMI Inbound Gateway + + The RMI Inbound Gateway now supports an error-channel attribute. See + . + +
+
+ XsltPayloadTransformer + + You can now specify the transformer factory class name using the + transformer-factory-class attribute. See
diff --git a/src/reference/docbook/xml.xml b/src/reference/docbook/xml.xml index 5ee55ef17a..6bd803a776 100644 --- a/src/reference/docbook/xml.xml +++ b/src/reference/docbook/xml.xml @@ -340,12 +340,8 @@ Transformer. When configuring XML transformers as beans in Spring Integration, you would normally configure the Transformer - in conjunction with either a - MessageTransformingChannelInterceptor - or a MessageTransformingHandler. - This allows the transformer to be used as either an interceptor, - which transforms the message as it is sent or received to the - Channel, or as an Endpoint. + in conjunction with a MessageTransformingHandler. + This allows the transformer to be used as an Endpoint. Finally, the namespace support will be discussed, which allows for the simple configuration of the transformers as elements in XML.