INT-3778: STOMP Namespace and Documentation

JIRA: https://jira.spring.io/browse/INT-3778

* Add Namespace support for STOMP adapters
* Document the STOMP module
* Fix race condition in the `AbstractStompSessionManager`
* Add `handleTransportError` to the `StompInboundChannelAdapter` and `StompMessageHandler` to log errors during STOMP interactions
* Fix `StompMessageHandler` to handle `RECEIPT` in case of `RECEIPT` header existence, not the common `autoReceipt` option
which can be disable, but the `RECEIPT` header may be present in the message to send
* Increase logging level for the STOMP tests to trace sporadic failures on the CI Server
* Fix several typos

INT-3778: Doc Polishing
This commit is contained in:
Artem Bilan
2015-08-04 11:06:23 -04:00
committed by Gary Russell
parent e82bfdc9a6
commit d89dabe72f
17 changed files with 943 additions and 24 deletions

View File

@@ -71,7 +71,6 @@ public class StompServerIntegrationTests {
int port = SocketUtils.findAvailableTcpPort(61613);
activeMQBroker = new BrokerService();
activeMQBroker.addConnector("stomp://127.0.0.1:" + port);
activeMQBroker.setStartAsync(false);
activeMQBroker.setPersistent(false);
activeMQBroker.setUseJmx(false);
activeMQBroker.getSystemUsage().getMemoryUsage().setLimit(1024 * 1024 * 5);

View File

@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-stomp="http://www.springframework.org/schema/integration/stomp"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="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
http://www.springframework.org/schema/integration/stomp
http://www.springframework.org/schema/integration/stomp/spring-integration-stomp.xsd">
<bean id="stompSessionManager" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="org.springframework.integration.stomp.StompSessionManager"/>
</bean>
<bean id="stompHeaderMapper" class="org.springframework.integration.stomp.support.StompHeaderMapper"/>
<int-stomp:inbound-channel-adapter id="defaultInboundAdapter" stomp-session-manager="stompSessionManager"/>
<int-stomp:inbound-channel-adapter id="customInboundAdapter"
stomp-session-manager="stompSessionManager"
auto-startup="false"
payload-type="java.lang.Integer"
destinations="foo"
role="bar"
mapped-headers="foo, bar"
channel="inboundChannel"
error-channel="errorChannel"
send-timeout="2000"
phase="200"/>
<int:channel id="inboundChannel"/>
<!-- Invalid config -->
<!--<int-stomp:inbound-channel-adapter id="invalidInboundAdapter"
stomp-session-manager="stompSessionManager"
header-mapper="stompHeaderMapper"
mapped-headers="foo, bar"/>-->
<!-- Invalid config -->
<int-stomp:outbound-channel-adapter id="defaultOutboundAdapter" stomp-session-manager="stompSessionManager"/>
<int-stomp:outbound-channel-adapter id="customOutboundAdapter"
stomp-session-manager="stompSessionManager"
auto-startup="false"
phase="100"
role="foo"
destination="baz"
header-mapper="stompHeaderMapper"
channel="outboundChannel"/>
<int:channel id="outboundChannel"/>
<!-- Invalid config -->
<!--<int-stomp:outbound-channel-adapter id="invalidOutboundAdapter"
stomp-session-manager="stompSessionManager"
header-mapper="stompHeaderMapper"
mapped-headers="foo, bar"/>-->
<!-- Invalid config -->
</beans>

View File

@@ -0,0 +1,171 @@
/*
* Copyright 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.
*/
package org.springframework.integration.stomp.config;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.util.Collections;
import java.util.List;
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.SmartLifecycle;
import org.springframework.integration.endpoint.AbstractEndpoint;
import org.springframework.integration.mapping.HeaderMapper;
import org.springframework.integration.stomp.StompSessionManager;
import org.springframework.integration.stomp.inbound.StompInboundChannelAdapter;
import org.springframework.integration.support.SmartLifecycleRoleController;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.MultiValueMap;
/**
* @author Artem Bilan
* @since 4.2
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@DirtiesContext
public class StompAdaptersParserTests {
@Autowired
private StompSessionManager stompSessionManager;
@Autowired
private HeaderMapper<?> headerMapper;
@Autowired
@Qualifier("defaultInboundAdapter")
private MessageChannel defaultInboundAdapterChannel;
@Autowired
private MessageChannel errorChannel;
@Autowired
private MessageChannel inboundChannel;
@Autowired
@Qualifier("defaultInboundAdapter.adapter")
private StompInboundChannelAdapter defaultInboundAdapter;
@Autowired
private StompInboundChannelAdapter customInboundAdapter;
@Autowired
@Qualifier("defaultOutboundAdapter")
private MessageChannel defaultOutboundAdapterChannel;
@Autowired
@Qualifier("defaultOutboundAdapter.handler")
private MessageHandler defaultOutboundAdapterHandler;
@Autowired
@Qualifier("defaultOutboundAdapter.adapter")
private AbstractEndpoint defaultOutboundAdapter;
@Autowired
private MessageChannel outboundChannel;
@Autowired
@Qualifier("customOutboundAdapter.handler")
private MessageHandler customOutboundAdapterHandler;
@Autowired
@Qualifier("customOutboundAdapter")
private AbstractEndpoint customOutboundAdapter;
@Autowired
private SmartLifecycleRoleController roleController;
@Test
public void testParsers() {
assertSame(this.defaultInboundAdapterChannel,
TestUtils.getPropertyValue(this.defaultInboundAdapter, "outputChannel"));
assertSame(this.stompSessionManager,
TestUtils.getPropertyValue(this.defaultInboundAdapter, "stompSessionManager"));
assertNull(TestUtils.getPropertyValue(this.defaultInboundAdapter, "errorChannel"));
Object headerMapper = TestUtils.getPropertyValue(this.defaultInboundAdapter, "headerMapper");
assertNotNull(headerMapper);
assertNotSame(this.headerMapper, headerMapper);
assertEquals(String.class, TestUtils.getPropertyValue(this.defaultInboundAdapter, "payloadType", Class.class));
assertTrue(TestUtils.getPropertyValue(this.defaultInboundAdapter, "autoStartup", Boolean.class));
assertSame(this.inboundChannel,
TestUtils.getPropertyValue(this.customInboundAdapter, "outputChannel"));
assertSame(this.stompSessionManager,
TestUtils.getPropertyValue(this.customInboundAdapter, "stompSessionManager"));
assertSame(this.errorChannel, TestUtils.getPropertyValue(this.customInboundAdapter, "errorChannel"));
assertEquals(Collections.singleton("foo"),
TestUtils.getPropertyValue(this.customInboundAdapter, "destinations"));
headerMapper = TestUtils.getPropertyValue(this.customInboundAdapter, "headerMapper");
assertNotNull(headerMapper);
assertNotSame(this.headerMapper, headerMapper);
assertArrayEquals(new String[] {"bar", "foo"},
TestUtils.getPropertyValue(headerMapper, "inboundHeaderNames", String[].class));
assertEquals(Integer.class, TestUtils.getPropertyValue(this.customInboundAdapter, "payloadType", Class.class));
assertFalse(TestUtils.getPropertyValue(this.customInboundAdapter, "autoStartup", Boolean.class));
assertEquals(200, TestUtils.getPropertyValue(this.customInboundAdapter, "phase"));
assertEquals(2000L, TestUtils.getPropertyValue(this.customInboundAdapter, "messagingTemplate.sendTimeout"));
assertSame(this.stompSessionManager,
TestUtils.getPropertyValue(this.defaultOutboundAdapterHandler, "stompSessionManager"));
headerMapper = TestUtils.getPropertyValue(this.defaultOutboundAdapterHandler, "headerMapper");
assertNotNull(headerMapper);
assertNotSame(this.headerMapper, headerMapper);
assertNull(TestUtils.getPropertyValue(this.defaultOutboundAdapterHandler, "destinationExpression"));
assertSame(this.defaultOutboundAdapterHandler,
TestUtils.getPropertyValue(this.defaultOutboundAdapter, "handler"));
assertSame(this.defaultOutboundAdapterChannel,
TestUtils.getPropertyValue(this.defaultOutboundAdapter, "inputChannel"));
assertTrue(TestUtils.getPropertyValue(this.defaultOutboundAdapter, "autoStartup", Boolean.class));
assertSame(this.stompSessionManager,
TestUtils.getPropertyValue(this.customOutboundAdapterHandler, "stompSessionManager"));
assertSame(this.headerMapper, TestUtils.getPropertyValue(this.customOutboundAdapterHandler, "headerMapper"));
assertEquals("baz",
TestUtils.getPropertyValue(this.customOutboundAdapterHandler, "destinationExpression.literalValue"));
assertSame(this.customOutboundAdapterHandler,
TestUtils.getPropertyValue(this.customOutboundAdapter, "handler"));
assertSame(this.outboundChannel, TestUtils.getPropertyValue(this.customOutboundAdapter, "inputChannel"));
assertFalse(TestUtils.getPropertyValue(this.customOutboundAdapter, "autoStartup", Boolean.class));
assertEquals(100, TestUtils.getPropertyValue(this.customOutboundAdapter, "phase"));
@SuppressWarnings("unchecked")
MultiValueMap<String, SmartLifecycle> lifecycles = (MultiValueMap<String, SmartLifecycle>)
TestUtils.getPropertyValue(this.roleController, "lifecycles", MultiValueMap.class);
assertTrue(lifecycles.containsKey("bar"));
List<SmartLifecycle> bars = lifecycles.get("bar");
bars.contains(this.customInboundAdapter);
assertTrue(lifecycles.containsKey("foo"));
List<SmartLifecycle> foos = lifecycles.get("bar");
bars.contains(this.customOutboundAdapter);
}
}

View File

@@ -4,5 +4,6 @@ log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %c{1} [%t] : %m%n
log4j.category.org.springframework.integration=WARN
log4j.category.org.springframework.integration.stomp=WARN
log4j.category.org.springframework.messaging=DEBUG
log4j.category.org.springframework.integration=DEBUG
#log4j.category.org.springframework.integration.stomp=WARN