INT-2230: Fix for Double Global Wire-Taps
JIRA: https://jira.spring.io/browse/INT-2230 Previously two global `<wire-tap>`s with the same `id` registered two `GlobalChannelInterceptorWrapper` wrappers with generated names for the same (last) `WireTap`. Hence the same `Message` has been sent to the the `wire-tap channel` twice (or more). Fix the issue with overriding `GlobalChannelInterceptorParser#resolveId` with the `.globalChannelInterceptor` suffix. Therefore the last `GlobalChannelInterceptorWrapper` wins overriding all others, if all our `<wire-tap>`s has the same `id`. INT-2230: Add `id` to the global `channel-interceptor` Polishing
This commit is contained in:
committed by
Gary Russell
parent
2214b48aa0
commit
61e959377d
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -48,7 +48,7 @@ public class GlobalChannelInterceptorParser extends AbstractBeanDefinitionParser
|
||||
private static final String REF_ATTRIBUTE = "ref";
|
||||
|
||||
@Override
|
||||
protected boolean shouldGenerateId() {
|
||||
protected boolean shouldGenerateIdAsFallback() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* 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.
|
||||
@@ -15,12 +15,15 @@ package org.springframework.integration.config.xml;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
|
||||
/**
|
||||
* Parser for the top level 'wire-tap' element
|
||||
* @author David Turanski
|
||||
* @author Artem Bilan
|
||||
* @since 2.1
|
||||
*
|
||||
*/
|
||||
@@ -32,4 +35,10 @@ public class GlobalWireTapParser extends GlobalChannelInterceptorParser {
|
||||
return new RuntimeBeanReference(wireTapBeanName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
|
||||
throws BeanDefinitionStoreException {
|
||||
return super.resolveId(element, definition, parserContext) + ".globalChannelInterceptor";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4079,6 +4079,7 @@
|
||||
<xsd:sequence>
|
||||
<xsd:any namespace="##any" processContents="strict" minOccurs="0" maxOccurs="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="id" type="xsd:string" use="optional" />
|
||||
<xsd:attribute name="pattern" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
@@ -2,22 +2,27 @@
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:p="http://www.springframework.org/schema/p"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<int:channel id="inputA"/>
|
||||
|
||||
<int:channel-interceptor>
|
||||
<int:channel-interceptor id="globalChannelInterceptor">
|
||||
<int:wire-tap channel="wiretap1"/>
|
||||
</int:channel-interceptor>
|
||||
|
||||
<int:channel id="wiretap1">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel-interceptor id="globalChannelInterceptor">
|
||||
<int:wire-tap channel="wiretap"/>
|
||||
</int:channel-interceptor>
|
||||
|
||||
|
||||
<int:channel id="wiretap">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
|
||||
<int:bridge input-channel="inputA" output-channel="nullChannel"/>
|
||||
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,43 +18,51 @@ package org.springframework.integration.channel.interceptor;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* @author David Turanski
|
||||
* @author Artem Bilan
|
||||
* @since 2.0
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@DirtiesContext
|
||||
public class GlobalChannelInterceptorSubElementTests {
|
||||
@Autowired
|
||||
ApplicationContext applicationContext;
|
||||
|
||||
|
||||
|
||||
@Autowired
|
||||
@Qualifier("inputA")
|
||||
MessageChannel inputA;
|
||||
|
||||
|
||||
@Autowired
|
||||
@Qualifier("wiretap")
|
||||
PollableChannel wiretapChannel;
|
||||
|
||||
|
||||
@Autowired
|
||||
@Qualifier("wiretap1")
|
||||
PollableChannel wiretap1;
|
||||
|
||||
@Test
|
||||
public void testWiretapSubElement(){
|
||||
inputA.send(new GenericMessage<String>("hello"));
|
||||
Message<?> result = wiretapChannel.receive(100);
|
||||
public void testWiretapSubElement() {
|
||||
this.inputA.send(new GenericMessage<String>("hello"));
|
||||
Message<?> result = this.wiretapChannel.receive(100);
|
||||
assertNotNull(result);
|
||||
assertEquals("hello",result.getPayload());
|
||||
assertEquals("hello", result.getPayload());
|
||||
assertNull(this.wiretapChannel.receive(1));
|
||||
assertNull(this.wiretap1.receive(1));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,34 +1,46 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://www.springframework.org/schema/integration"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://www.springframework.org/schema/integration"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
<message-history/>
|
||||
|
||||
<channel id="channel"/>
|
||||
|
||||
<channel id="wiretap-single">
|
||||
<queue/>
|
||||
</channel>
|
||||
|
||||
<channel id="wiretap-all">
|
||||
<queue/>
|
||||
</channel>
|
||||
|
||||
<channel id="output">
|
||||
<queue/>
|
||||
</channel>
|
||||
|
||||
<channel id="random-channel"/>
|
||||
|
||||
<bridge input-channel="channel" output-channel="output"/>
|
||||
<bridge input-channel="random-channel" output-channel="output"/>
|
||||
|
||||
<!-- This wiretap targets a single channel -->
|
||||
<wire-tap id="wiretap-single-channel" channel="wiretap-single" pattern="channel" order="0"/>
|
||||
|
||||
<!-- This wiretap targets all channels -->
|
||||
<wire-tap id="wiretap-all-channels" channel="wiretap-all"/>
|
||||
|
||||
<message-history/>
|
||||
|
||||
<channel id="channel"/>
|
||||
|
||||
<channel id="wiretap-single">
|
||||
<queue/>
|
||||
</channel>
|
||||
|
||||
<channel id="wiretap-all">
|
||||
<queue/>
|
||||
</channel>
|
||||
|
||||
<channel id="wiretap-all2">
|
||||
<queue/>
|
||||
</channel>
|
||||
|
||||
<channel id="output">
|
||||
<queue/>
|
||||
</channel>
|
||||
|
||||
<channel id="random-channel"/>
|
||||
|
||||
<bridge input-channel="channel" output-channel="output"/>
|
||||
<bridge input-channel="random-channel" output-channel="output"/>
|
||||
|
||||
<!-- This wiretap targets a single channel -->
|
||||
<wire-tap id="wiretap-single-channel" channel="wiretap-single" pattern="channel" order="0"/>
|
||||
|
||||
|
||||
<!-- This second global wire-tap caused an issue previously when the second GlobalChannelInterceptorWrapper
|
||||
was registered in the application context and the message was send twice to the same (last) channel.
|
||||
In other words two GlobalChannelInterceptorWrappers were defined for the same (last) WireTap.
|
||||
According to the Spring logic the second bean definition should win. -->
|
||||
<wire-tap id="wiretap-all-channels" channel="wiretap-all2"/>
|
||||
|
||||
<!-- This wiretap targets all channels -->
|
||||
<wire-tap id="wiretap-all-channels" channel="wiretap-all"/>
|
||||
|
||||
|
||||
</beans:beans>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
@@ -10,6 +10,7 @@
|
||||
* 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.channel.interceptor;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@@ -25,77 +26,85 @@ import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author David Turanski
|
||||
* @author Gary Russell
|
||||
*
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@DirtiesContext
|
||||
public class GlobalWireTapTests {
|
||||
|
||||
|
||||
@Autowired
|
||||
@Qualifier("channel")
|
||||
MessageChannel channel;
|
||||
@Autowired
|
||||
@Qualifier("channel")
|
||||
MessageChannel channel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("random-channel")
|
||||
MessageChannel anotherChannel;
|
||||
@Autowired
|
||||
@Qualifier("random-channel")
|
||||
MessageChannel anotherChannel;
|
||||
|
||||
|
||||
@Autowired
|
||||
@Qualifier("wiretap-single")
|
||||
PollableChannel wiretapSingle;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("wiretap-single")
|
||||
PollableChannel wiretapSingle;
|
||||
@Autowired
|
||||
@Qualifier("wiretap-all")
|
||||
PollableChannel wiretapAll;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("wiretap-all")
|
||||
PollableChannel wiretapAll;
|
||||
@Autowired
|
||||
@Qualifier("wiretap-all2")
|
||||
PollableChannel wiretapAll2;
|
||||
|
||||
|
||||
@Test
|
||||
public void testWireTapsOnTargetedChannel() {
|
||||
Message<?> message = new GenericMessage<String>("hello");
|
||||
this.channel.send(message);
|
||||
Message<?> wireTapMessage = this.wiretapSingle.receive(100);
|
||||
assertNotNull(wireTapMessage);
|
||||
|
||||
@Test
|
||||
public void testWireTapsOnTargetedChannel(){
|
||||
Message<?> message = new GenericMessage<String>("hello");
|
||||
channel.send(message);
|
||||
Message <?> wireTapMessage = wiretapSingle.receive(100);
|
||||
assertNotNull(wireTapMessage);
|
||||
// There should be three messages on this channel.
|
||||
// One for 'channel', one for 'output', and one for 'wiretapSingle'.
|
||||
wireTapMessage = this.wiretapAll.receive(100);
|
||||
int msgCount = 0;
|
||||
while (wireTapMessage != null) {
|
||||
msgCount++;
|
||||
assertEquals(wireTapMessage.getPayload(), message.getPayload());
|
||||
wireTapMessage = this.wiretapAll.receive(100);
|
||||
}
|
||||
|
||||
//There should be three messages on this channel. One for 'channel', one for 'output', and one for 'wiretapSingle'.
|
||||
wireTapMessage = wiretapAll.receive(100);
|
||||
int msgCount=0;
|
||||
while (wireTapMessage != null){
|
||||
msgCount++;
|
||||
assertEquals(wireTapMessage.getPayload(),message.getPayload());
|
||||
wireTapMessage = wiretapAll.receive(100);
|
||||
}
|
||||
assertEquals(3, msgCount);
|
||||
|
||||
assertEquals(3,msgCount);
|
||||
}
|
||||
assertNull(this.wiretapAll2.receive(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWireTapsOnRandomChannel(){
|
||||
Message<?> message = new GenericMessage<String>("hello");
|
||||
anotherChannel.send(message);
|
||||
@Test
|
||||
public void testWireTapsOnRandomChannel() {
|
||||
Message<?> message = new GenericMessage<String>("hello");
|
||||
anotherChannel.send(message);
|
||||
|
||||
//This time no message on wiretapSingle
|
||||
Message <?> wireTapMessage = wiretapSingle.receive(100);
|
||||
assertNull(wireTapMessage);
|
||||
//This time no message on wiretapSingle
|
||||
Message<?> wireTapMessage = wiretapSingle.receive(100);
|
||||
assertNull(wireTapMessage);
|
||||
|
||||
//There should be two messages on this channel. One for 'channel' and one for 'output'
|
||||
wireTapMessage = wiretapAll.receive(100);
|
||||
int msgCount=0;
|
||||
while (wireTapMessage != null){
|
||||
msgCount++;
|
||||
assertEquals(wireTapMessage.getPayload(),message.getPayload());
|
||||
wireTapMessage = wiretapAll.receive(100);
|
||||
}
|
||||
//There should be two messages on this channel. One for 'channel' and one for 'output'
|
||||
wireTapMessage = wiretapAll.receive(100);
|
||||
int msgCount = 0;
|
||||
while (wireTapMessage != null) {
|
||||
msgCount++;
|
||||
assertEquals(wireTapMessage.getPayload(), message.getPayload());
|
||||
wireTapMessage = wiretapAll.receive(100);
|
||||
}
|
||||
|
||||
assertEquals(2,msgCount);
|
||||
}
|
||||
assertEquals(2, msgCount);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user