INT-3500: Consider to add "error-channel" to the <enricher>
JIRA: https://jira.spring.io/browse/INT-3500 * add 'error-channel' to the <enricher> component * delegate errorChannel to the internal gateway in ContentEnricher * added tests for xml based and java based enrichers with error channels INT-3500: Consider to add "error-channel" to the <enricher> * Fixed typos and comments * Reworked xml integration test to use the outputChannel and increased timeout * Added overview in whats-new doc INT-3500: Consider to add "error-channel" to the <enricher> * Ensure requestChannel is set if an errorChannel is set * Increased timeout to fix unit test * Added details to content-enricher ref doc Polishing
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans:beans xmlns="http://www.springframework.org/schema/integration"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration.xsd">
|
||||
|
||||
<channel id="inputChannel"/>
|
||||
|
||||
<channel id="requestChannel"/>
|
||||
|
||||
<channel id="errChannel"/>
|
||||
|
||||
<channel id="outputChannel">
|
||||
<queue />
|
||||
</channel>
|
||||
|
||||
<enricher id="enricher"
|
||||
input-channel="inputChannel" request-channel="requestChannel"
|
||||
output-channel="outputChannel" error-channel="errChannel">
|
||||
<property name="name" expression="'Mr. ' + payload.name"/>
|
||||
</enricher>
|
||||
|
||||
</beans:beans>
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.config.xml;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* Tests the error-channel in an enricher to produce
|
||||
* a default object in case of downstream failure.
|
||||
*
|
||||
* @author Kris Jacyna
|
||||
* @since 4.1
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
public class EnricherParserTests5 {
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext context;
|
||||
|
||||
|
||||
@Test
|
||||
public void errorChannelTest() {
|
||||
|
||||
class ErrorThrower extends AbstractReplyProducingMessageHandler {
|
||||
@Override
|
||||
protected Object handleRequestMessage(Message<?> requestMessage) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
class DefaultTargetProducer extends AbstractReplyProducingMessageHandler {
|
||||
@Override
|
||||
protected Object handleRequestMessage(Message<?> requestMessage) {
|
||||
final Target defaultTarget = new Target();
|
||||
defaultTarget.setName("Default");
|
||||
return defaultTarget;
|
||||
}
|
||||
}
|
||||
|
||||
context.getBean("requestChannel", DirectChannel.class).subscribe(new ErrorThrower());
|
||||
context.getBean("errChannel", DirectChannel.class).subscribe(new DefaultTargetProducer());
|
||||
|
||||
Target original = new Target();
|
||||
original.setName("John");
|
||||
Message<?> request = MessageBuilder.withPayload(original).build();
|
||||
|
||||
context.getBean("inputChannel", DirectChannel.class).send(request);
|
||||
|
||||
Message<?> reply = context.getBean("outputChannel", PollableChannel.class).receive(10000);
|
||||
Target enriched = (Target) reply.getPayload();
|
||||
assertEquals("Mr. Default", enriched.getName());
|
||||
}
|
||||
|
||||
|
||||
public static class Target {
|
||||
|
||||
private volatile String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -57,6 +57,7 @@ import org.springframework.scheduling.support.PeriodicTrigger;
|
||||
* @author Gunnar Hillert
|
||||
* @author Artem Bilan
|
||||
* @author Gary Russell
|
||||
* @author Kris Jacyna
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
@@ -85,9 +86,9 @@ public class ContentEnricherTests {
|
||||
public void replyChannelReplyTimingOut() throws Exception {
|
||||
|
||||
final long requestTimeout = 500L;
|
||||
final long replyTimeout = 700L;
|
||||
final long replyTimeout = 700L;
|
||||
|
||||
final DirectChannel replyChannel = new DirectChannel();
|
||||
final DirectChannel replyChannel = new DirectChannel();
|
||||
final QueueChannel requestChannel = new QueueChannel(1);
|
||||
|
||||
final ContentEnricher enricher = new ContentEnricher();
|
||||
@@ -144,10 +145,11 @@ public class ContentEnricherTests {
|
||||
Message<?> requestMessage = MessageBuilder.withPayload(target).setReplyChannel(replyChannel).build();
|
||||
|
||||
try {
|
||||
enricher.handleMessage(requestMessage);
|
||||
enricher.handleMessage(requestMessage);
|
||||
}
|
||||
catch (ReplyRequiredException e) {
|
||||
assertEquals("No reply produced by handler 'Enricher', and its 'requiresReply' property is set to true.", e.getMessage());
|
||||
assertEquals("No reply produced by handler 'Enricher', and its 'requiresReply' property is set to true.",
|
||||
e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -161,7 +163,7 @@ public class ContentEnricherTests {
|
||||
final String requestChannelName = "Request_Channel";
|
||||
final long requestTimeout = 200L;
|
||||
|
||||
QueueChannel replyChannel = new QueueChannel();
|
||||
QueueChannel replyChannel = new QueueChannel();
|
||||
QueueChannel requestChannel = new RendezvousChannel();
|
||||
requestChannel.setBeanName(requestChannelName);
|
||||
|
||||
@@ -179,8 +181,7 @@ public class ContentEnricherTests {
|
||||
}
|
||||
catch (MessageDeliveryException e) {
|
||||
assertEquals("failed to send message to channel '" + requestChannelName
|
||||
+ "' within timeout: " + requestTimeout, e.getMessage());
|
||||
return;
|
||||
+ "' within timeout: " + requestTimeout, e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -216,7 +217,7 @@ public class ContentEnricherTests {
|
||||
@Test
|
||||
public void setReplyChannelWithoutRequestChannel() {
|
||||
|
||||
QueueChannel replyChannel = new QueueChannel();
|
||||
QueueChannel replyChannel = new QueueChannel();
|
||||
|
||||
ContentEnricher enricher = new ContentEnricher();
|
||||
enricher.setReplyChannel(replyChannel);
|
||||
@@ -287,8 +288,8 @@ public class ContentEnricherTests {
|
||||
@Test
|
||||
public void testContentEnricherWithNullRequestChannel() {
|
||||
|
||||
ContentEnricher enricher = new ContentEnricher();
|
||||
enricher.setReplyChannel(new QueueChannel());
|
||||
ContentEnricher enricher = new ContentEnricher();
|
||||
enricher.setReplyChannel(new QueueChannel());
|
||||
enricher.setBeanFactory(mock(BeanFactory.class));
|
||||
|
||||
try {
|
||||
@@ -383,7 +384,7 @@ public class ContentEnricherTests {
|
||||
enricher.afterPropertiesSet();
|
||||
|
||||
TargetUser target = new TargetUser();
|
||||
target.setName("replace me");
|
||||
target.setName("replace me");
|
||||
|
||||
Message<?> requestMessage = MessageBuilder.withPayload(target).setReplyChannel(replyChannel).build();
|
||||
enricher.handleMessage(requestMessage);
|
||||
@@ -416,12 +417,12 @@ public class ContentEnricherTests {
|
||||
enricher.afterPropertiesSet();
|
||||
|
||||
UncloneableTargetUser target = new UncloneableTargetUser();
|
||||
target.setName("replace me");
|
||||
target.setName("replace me");
|
||||
|
||||
Message<?> requestMessage = MessageBuilder.withPayload(target).setReplyChannel(replyChannel).build();
|
||||
|
||||
try {
|
||||
enricher.handleMessage(requestMessage);
|
||||
enricher.handleMessage(requestMessage);
|
||||
}
|
||||
catch (MessageHandlingException e) {
|
||||
assertThat(e.getMessage(), containsString("Failed to clone payload object"));
|
||||
@@ -469,6 +470,56 @@ public class ContentEnricherTests {
|
||||
assertTrue(enricher.isRunning());
|
||||
}
|
||||
|
||||
/**
|
||||
* In this test a {@link Target} message is passed into a {@link ContentEnricher}.
|
||||
* The Enricher passes the message to a "request-channel" to a handler which throws
|
||||
* an exception. The {@link ContentEnricher} then uses the error flow and consults
|
||||
* the "error-channel" which returns a alternative {@link Target}.
|
||||
*/
|
||||
@Test
|
||||
public void testErrorChannel() throws Exception {
|
||||
|
||||
final DirectChannel requestChannel = new DirectChannel();
|
||||
requestChannel.subscribe(new AbstractReplyProducingMessageHandler() {
|
||||
@Override
|
||||
protected Object handleRequestMessage(Message<?> requestMessage) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
final DirectChannel errorChannel = new DirectChannel();
|
||||
errorChannel.subscribe(new AbstractReplyProducingMessageHandler() {
|
||||
@Override
|
||||
protected Object handleRequestMessage(Message<?> requestMessage) {
|
||||
return new Target("failed");
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
final QueueChannel replyChannel = new QueueChannel();
|
||||
|
||||
final ContentEnricher enricher = new ContentEnricher();
|
||||
enricher.setRequestChannel(requestChannel);
|
||||
enricher.setErrorChannel(errorChannel);
|
||||
|
||||
SpelExpressionParser parser = new SpelExpressionParser();
|
||||
Map<String, Expression> propertyExpressions = new HashMap<String, Expression>();
|
||||
propertyExpressions.put("name", parser.parseExpression("payload.name + ' target'"));
|
||||
|
||||
enricher.setPropertyExpressions(propertyExpressions);
|
||||
enricher.setBeanFactory(mock(BeanFactory.class));
|
||||
enricher.afterPropertiesSet();
|
||||
|
||||
final Target target = new Target("replace me");
|
||||
Message<?> requestMessage = MessageBuilder.withPayload(target).setReplyChannel(replyChannel).build();
|
||||
|
||||
enricher.handleMessage(requestMessage);
|
||||
Message<?> reply = replyChannel.receive(10000);
|
||||
Target result = (Target) reply.getPayload();
|
||||
assertEquals("failed target", result.getName());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final class Source {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user