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:
committed by
Gary Russell
parent
e82bfdc9a6
commit
d89dabe72f
@@ -154,7 +154,7 @@ public class HttpInboundEndpointParser extends AbstractSingleBeanDefinitionParse
|
||||
|
||||
if (StringUtils.hasText(headerMapper)) {
|
||||
if (hasMappedRequestHeaders || hasMappedResponseHeaders) {
|
||||
parserContext.getReaderContext().error("Neither 'mappped-request-headers' or 'mapped-response-headers' " +
|
||||
parserContext.getReaderContext().error("Neither 'mapped-request-headers' or 'mapped-response-headers' " +
|
||||
"attributes are allowed when a 'header-mapper' has been specified.", parserContext.extractSource(element));
|
||||
}
|
||||
builder.addPropertyReference("headerMapper", headerMapper);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.integration.stomp;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -178,7 +179,8 @@ public abstract class AbstractStompSessionManager implements StompSessionManager
|
||||
|
||||
private static class CompositeStompSessionHandler extends StompSessionHandlerAdapter {
|
||||
|
||||
private final List<StompSessionHandler> delegates = new ArrayList<StompSessionHandler>();
|
||||
private final List<StompSessionHandler> delegates =
|
||||
Collections.synchronizedList(new ArrayList<StompSessionHandler>());
|
||||
|
||||
private volatile StompSession session;
|
||||
|
||||
@@ -188,41 +190,53 @@ public abstract class AbstractStompSessionManager implements StompSessionManager
|
||||
if (this.session != null) {
|
||||
delegate.afterConnected(this.session, this.connectedHeaders);
|
||||
}
|
||||
this.delegates.add(delegate);
|
||||
synchronized (this.delegates) {
|
||||
this.delegates.add(delegate);
|
||||
}
|
||||
}
|
||||
|
||||
void removeHandler(StompSessionHandler delegate) {
|
||||
this.delegates.remove(delegate);
|
||||
synchronized (this.delegates) {
|
||||
this.delegates.remove(delegate);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterConnected(StompSession session, StompHeaders connectedHeaders) {
|
||||
this.session = session;
|
||||
this.connectedHeaders = connectedHeaders;
|
||||
for (StompSessionHandler delegate : this.delegates) {
|
||||
delegate.afterConnected(session, connectedHeaders);
|
||||
synchronized (this.delegates) {
|
||||
for (StompSessionHandler delegate : this.delegates) {
|
||||
delegate.afterConnected(session, connectedHeaders);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleException(StompSession session, StompCommand command, StompHeaders headers, byte[] payload,
|
||||
Throwable exception) {
|
||||
for (StompSessionHandler delegate : this.delegates) {
|
||||
delegate.handleException(session, command, headers, payload, exception);
|
||||
synchronized (this.delegates) {
|
||||
for (StompSessionHandler delegate : this.delegates) {
|
||||
delegate.handleException(session, command, headers, payload, exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleTransportError(StompSession session, Throwable exception) {
|
||||
for (StompSessionHandler delegate : this.delegates) {
|
||||
delegate.handleTransportError(session, exception);
|
||||
synchronized (this.delegates) {
|
||||
for (StompSessionHandler delegate : this.delegates) {
|
||||
delegate.handleTransportError(session, exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleFrame(StompHeaders headers, Object payload) {
|
||||
for (StompSessionHandler delegate : this.delegates) {
|
||||
delegate.handleFrame(headers, payload);
|
||||
synchronized (this.delegates) {
|
||||
for (StompSessionHandler delegate : this.delegates) {
|
||||
delegate.handleFrame(headers, payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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 org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.stomp.support.StompHeaderMapper;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Artem Bilan
|
||||
* @since 4.2
|
||||
*/
|
||||
abstract class StompAdapterParserUtils {
|
||||
|
||||
static void configureStompAdapter(BeanDefinitionBuilder builder, ParserContext parserContext, Element element) {
|
||||
String stompSessionManager = element.getAttribute("stomp-session-manager");
|
||||
if (!StringUtils.hasText(stompSessionManager)) {
|
||||
parserContext.getReaderContext().error("The 'stomp-session-manager' is required", element);
|
||||
}
|
||||
builder.addConstructorArgReference(stompSessionManager);
|
||||
|
||||
String headerMapper = element.getAttribute("header-mapper");
|
||||
|
||||
String mappedHeaders = element.getAttribute("mapped-headers");
|
||||
|
||||
boolean hasMappedHeaders = StringUtils.hasText(mappedHeaders);
|
||||
|
||||
if (StringUtils.hasText(headerMapper)) {
|
||||
if (hasMappedHeaders) {
|
||||
parserContext.getReaderContext().error("The 'mapped-headers' " +
|
||||
"attribute is not allowed when a 'header-mapper' has been specified.",
|
||||
parserContext.extractSource(element));
|
||||
}
|
||||
builder.addPropertyReference("headerMapper", headerMapper);
|
||||
}
|
||||
else if (hasMappedHeaders) {
|
||||
BeanDefinitionBuilder headerMapperBuilder =
|
||||
BeanDefinitionBuilder.genericBeanDefinition(StompHeaderMapper.class);
|
||||
|
||||
// This is tricky a bit, but from one side the 'headerMapper' is an internal instance
|
||||
// and isn't accessible outside and from other side allow us to avoid extra 'boolean' variable
|
||||
headerMapperBuilder.addPropertyValue("inboundHeaderNames", mappedHeaders);
|
||||
headerMapperBuilder.addPropertyValue("outboundHeaderNames", mappedHeaders);
|
||||
|
||||
builder.addPropertyValue("headerMapper", headerMapperBuilder.getBeanDefinition());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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 org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.config.xml.AbstractChannelAdapterParser;
|
||||
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
|
||||
import org.springframework.integration.stomp.inbound.StompInboundChannelAdapter;
|
||||
|
||||
/**
|
||||
* The {@link AbstractSingleBeanDefinitionParser} implementation for
|
||||
* the {@code <stomp:inbound-channel-adapter/>} element.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
* @since 4.2
|
||||
*/
|
||||
public class StompInboundChannelAdapterParser extends AbstractChannelAdapterParser {
|
||||
|
||||
@Override
|
||||
protected AbstractBeanDefinition doParse(Element element, ParserContext parserContext, String channelName) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(StompInboundChannelAdapter.class);
|
||||
StompAdapterParserUtils.configureStompAdapter(builder, parserContext, element);
|
||||
builder.addConstructorArgValue(element.getAttribute("destinations"));
|
||||
builder.addPropertyReference("outputChannel", channelName);
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "error-channel");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "send-timeout");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "payload-type");
|
||||
return builder.getBeanDefinition();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,7 +25,8 @@ import org.springframework.integration.config.xml.AbstractIntegrationNamespaceHa
|
||||
public class StompNamespaceHandler extends AbstractIntegrationNamespaceHandler {
|
||||
|
||||
public void init() {
|
||||
|
||||
registerBeanDefinitionParser("inbound-channel-adapter", new StompInboundChannelAdapterParser());
|
||||
registerBeanDefinitionParser("outbound-channel-adapter", new StompOutboundChannelAdapterParser());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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 org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.config.xml.AbstractOutboundChannelAdapterParser;
|
||||
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
|
||||
import org.springframework.integration.stomp.outbound.StompMessageHandler;
|
||||
|
||||
/**
|
||||
* The {@link AbstractOutboundChannelAdapterParser} implementation for
|
||||
* the {@code <stomp:outbound-channel-adapter/>} element.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
* @since 4.2
|
||||
*/
|
||||
public class StompOutboundChannelAdapterParser extends AbstractOutboundChannelAdapterParser {
|
||||
|
||||
@Override
|
||||
protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(StompMessageHandler.class);
|
||||
StompAdapterParserUtils.configureStompAdapter(builder, parserContext, element);
|
||||
BeanDefinition expressionDef =
|
||||
IntegrationNamespaceUtils.createExpressionDefinitionFromValueOrExpression("destination",
|
||||
"destination-expression", parserContext, element, false);
|
||||
if (expressionDef != null) {
|
||||
builder.addPropertyValue("destinationExpression", expressionDef);
|
||||
}
|
||||
return builder.getBeanDefinition();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -292,6 +292,11 @@ public class StompInboundChannelAdapter extends MessageProducerSupport implement
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleTransportError(StompSession session, Throwable exception) {
|
||||
logger.error("STOMP transport error for session: [" + session + "]", exception);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ public class StompMessageHandler extends AbstractMessageHandler implements Appli
|
||||
}
|
||||
|
||||
final StompSession.Receiptable receiptable = this.stompSession.send(stompHeaders, message.getPayload());
|
||||
if (this.stompSessionManager.isAutoReceiptEnabled()) {
|
||||
if (receiptable.getReceiptId() != null) {
|
||||
final String destination = stompHeaders.getDestination();
|
||||
if (this.applicationEventPublisher != null) {
|
||||
receiptable.addReceiptTask(new Runnable() {
|
||||
@@ -199,6 +199,11 @@ public class StompMessageHandler extends AbstractMessageHandler implements Appli
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleTransportError(StompSession session, Throwable exception) {
|
||||
logger.error("STOMP transport error for session: [" + session + "]", exception);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsd:schema xmlns="http://www.springframework.org/schema/integration/websocket"
|
||||
<xsd:schema xmlns="http://www.springframework.org/schema/integration/stomp"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:tool="http://www.springframework.org/schema/tool"
|
||||
xmlns:integration="http://www.springframework.org/schema/integration"
|
||||
targetNamespace="http://www.springframework.org/schema/integration/websocket"
|
||||
targetNamespace="http://www.springframework.org/schema/integration/stomp"
|
||||
elementFormDefault="qualified"
|
||||
attributeFormDefault="unqualified">
|
||||
|
||||
@@ -19,5 +18,152 @@
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
|
||||
<xsd:element name="inbound-channel-adapter">
|
||||
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Configures an endpoint that will receive STOMP Messages using the provided
|
||||
'StompSessionManager'.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="stompAdapterType">
|
||||
<xsd:attribute name="destinations">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Comma-separated list of STOMP destination names to subscribe.
|
||||
The list of destinations (and therefore subscriptions) can be modified at runtime
|
||||
through the 'addDestination()' and 'removeDestination()' '@ManagedOperation's.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="error-channel">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Message Channel to which error Messages should be sent.
|
||||
</xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.messaging.MessageChannel"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="send-timeout">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Maximum amount of time in milliseconds to wait when sending a message
|
||||
to the channel if such channel may block.
|
||||
For example, a Queue Channel can block until space is available
|
||||
if its maximum capacity has been reached.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="payload-type" default="java.lang.String">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation source="java:java.lang.Class">
|
||||
Fully qualified name of the java type for the target 'payload'
|
||||
to convert from the incoming Stomp Message.
|
||||
Defaults to 'java.lang.String'.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="outbound-channel-adapter">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Configures an endpoint that will send a STOMP Message to the provided
|
||||
'StompSessionManager'.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="stompAdapterType">
|
||||
<xsd:choice minOccurs="0" maxOccurs="2">
|
||||
<xsd:element ref="integration:poller" minOccurs="0" maxOccurs="1"/>
|
||||
<xsd:element name="request-handler-advice-chain" type="integration:handlerAdviceChainType"
|
||||
minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:choice>
|
||||
<xsd:attribute name="destination">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Name of the destination to which STOMP Messages will be sent.
|
||||
Mutually exclusive with the 'destination-expression'.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="destination-expression" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
A SpEL expression to be evaluated at runtime against each Spring Integration Message as
|
||||
the root object.
|
||||
Mutually exclusive with the 'destination'.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:complexType name="stompAdapterType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Base type for the 'inbound-channel-adapter' and 'outbound-channel-adapter' elements.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:attribute name="stomp-session-manager" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
The reference to the 'StompSessionManager' bean, which encapsulates the low-level
|
||||
connection and StompSession handling operations. Required.
|
||||
</xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type
|
||||
type="org.springframework.integration.stomp.StompSessionManager"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="header-mapper">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Reference to a bean implementing 'HeaderMapper' that maps Spring Integration MessageHeaders to/from
|
||||
STOMP frame headers.
|
||||
This is mutually exclusive with 'mapped-headers'.
|
||||
Defaults to StompHeaderMapper.
|
||||
</xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type=" org.springframework.integration.mapping.HeaderMapper"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="mapped-headers">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Comma-separated list of names of STOMP Headers to be mapped from/to the STOMP frame headers.
|
||||
This can only be provided if the 'header-mapper' reference is not being set directly.
|
||||
The values in this list can also be simple patterns to be matched against
|
||||
the header names (e.g. "foo*" or "*foo").
|
||||
Special tokens 'STOMP_INBOUND_HEADERS' and 'STOMP_OUTBOUND_HEADERS' represent
|
||||
all the standard STOMP headers (content-length, receipt, heart-beat etc)
|
||||
for the inbound and outbound channel adapters respectively;
|
||||
they are included by default.
|
||||
If you wish to add your own headers, you must also include these tokens if you wish the
|
||||
standard headers to also be mapped or provide your own 'HeaderMapper'
|
||||
implementation using 'header-mapper'.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attributeGroup ref="integration:channelAdapterAttributes"/>
|
||||
</xsd:complexType>
|
||||
|
||||
</xsd:schema>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -88,6 +88,8 @@ include::./rmi.adoc[]
|
||||
|
||||
include::./sftp.adoc[]
|
||||
|
||||
include::./stomp.adoc[]
|
||||
|
||||
include::./stream.adoc[]
|
||||
|
||||
include::./syslog.adoc[]
|
||||
|
||||
333
src/reference/asciidoc/stomp.adoc
Normal file
333
src/reference/asciidoc/stomp.adoc
Normal file
@@ -0,0 +1,333 @@
|
||||
[[stomp]]
|
||||
== STOMP Support
|
||||
|
||||
[[stomp-introduction]]
|
||||
=== Introduction
|
||||
|
||||
Spring Integration _version 4.2_ introduced _STOMP Client_ support.
|
||||
It is based on the architecture, infrastructure and API from the Spring Framework's _messaging_ module, _stomp_ package.
|
||||
Many of Spring STOMP components (e.g. `StompSession` or `StompClientSupport`)
|
||||
are used within Spring Integration.
|
||||
For more information, please, refer to the http://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-stomp-client[Spring Framework STOMP Support]
|
||||
chapter in the Spring Framework reference manual.
|
||||
|
||||
[[stomp-overview]]
|
||||
=== Overview
|
||||
|
||||
To configure STOMP (Simple [or Streaming] Text Orientated Messaging Protocol) let's start with the _STOMP Client_ object.
|
||||
The Spring Framework provides these implementations:
|
||||
|
||||
* `WebSocketStompClient` - built on the Spring WebSocket API with support for standard JSR-356 WebSocket, Jetty 9,
|
||||
as well as SockJS for HTTP-based WebSocket emulation with SockJS Client.
|
||||
|
||||
* `Reactor2TcpStompClient` - built on `NettyTcpClient` from the `reactor-net` project.
|
||||
|
||||
Any other `StompClientSupport` implementation can be provided.
|
||||
See the JavaDocs of those classes for more information.
|
||||
|
||||
The `StompClientSupport` class is designed as a _factory_ to produce a `StompSession` for the provided
|
||||
`StompSessionHandler` and all the remaining work is done through the _callbacks_ to that `StompSessionHandler`
|
||||
and `StompSession` abstraction.
|
||||
With the Spring Integration _adapter_ abstraction, we
|
||||
need to provide some managed shared object to represent our application as a STOMP client with its unique session.
|
||||
For this purpose, Spring Integration provides the `StompSessionManager` abstraction to manage the _single_
|
||||
`StompSession` between any provided `StompSessionHandler`.
|
||||
This allows the use of _inbound_ or _outbound_ channel adapters (or both) for the particular STOMP Broker.
|
||||
See `StompSessionManager` (and its implementations) JavaDocs for more information.
|
||||
|
||||
[[stomp-inbound-adapter]]
|
||||
=== STOMP Inbound Channel Adapter
|
||||
|
||||
The `StompInboundChannelAdapter` is a one-stop `MessageProducer` component to subscribe our Spring Integration
|
||||
application to the provided STOMP destinations and receive messages from them, converted from the STOMP
|
||||
frames using the provided `MessageConverter` on the connected `StompSession`.
|
||||
The destinations (and therefore STOMP subscriptions) can be changed at runtime using appropriate `@ManagedOperation` s
|
||||
on the `StompInboundChannelAdapter`.
|
||||
|
||||
For more configuration options see <<stomp-namespace>> and the `StompInboundChannelAdapter` JavaDocs.
|
||||
|
||||
[[stomp-outbound-adapter]]
|
||||
=== STOMP Outbound Channel Adapter
|
||||
|
||||
The `StompMessageHandler` is the `MessageHandler` for the `<int-stomp:outbound-channel-adapter>`
|
||||
to send the outgoing `Message<?>` s to the STOMP `destination` (pre-configured or determined at runtime via a SpEL expression) STOMP through the `StompSession`, provided by the shared `StompSessionManager`.
|
||||
|
||||
For more configuration option see <<stomp-namespace>> and the `StompMessageHandler` JavaDocs.
|
||||
|
||||
[[stomp-headers]]
|
||||
=== STOMP Headers Mapping
|
||||
|
||||
The STOMP protocol provides _headers_ as part of frame; the entire structure of the STOMP frame
|
||||
has this format:
|
||||
|
||||
....
|
||||
COMMAND
|
||||
header1:value1
|
||||
header2:value2
|
||||
|
||||
Body^@
|
||||
....
|
||||
|
||||
Spring Framework provides `StompHeaders`, to represent these headers.
|
||||
See the JavaDocs for more details.
|
||||
STOMP frames are converted to/from `Message<?>` and these headers are mapped to/from `MessageHeaders`.
|
||||
Spring Integration provides a default `HeaderMapper` implementation for the STOMP adapters.
|
||||
The implementation is `StompHeaderMapper` which provides `fromHeaders()` and `toHeaders()` operations for the
|
||||
_inbound_ and _outbound_ adapters respectively.
|
||||
|
||||
As with many other Spring Integration modules, the `IntegrationStompHeaders` class has been
|
||||
introduced to map standard STOMP headers to `MessageHeaders` with `stomp_` as the header name prefix.
|
||||
In addition, all `MessageHeaders` with that prefix are mapped to the `StompHeaders` when sending to a destination.
|
||||
|
||||
For more information, see the JavaDocs of those classes and the `mapped-headers` attribute description in the
|
||||
<<stomp-namespace>>.
|
||||
|
||||
[[stomp-events]]
|
||||
=== STOMP Integration Events
|
||||
|
||||
Many STOMP operations are asynchronous, including error handling.
|
||||
For example, STOMP has a `RECEIPT` server frame that is returned when a client frame has requested one by addding
|
||||
the `RECEIPT` header.
|
||||
To provide access to these asynchronous events, Spring Integration emits `StompIntegrationEvent` s which can be
|
||||
obtained by implementing an `ApplicationListener` or using an event inbound channel adapter.
|
||||
|
||||
Specifically, a `StompExceptionEvent` is emitted from the `AbstractStompSessionManager`, when a
|
||||
`stompSessionListenableFuture` receives `onFailure()` in case of failure to connect to STOMP Broker.
|
||||
Another example is the `StompMessageHandler` which processes
|
||||
`ERROR` STOMP frames, which are server responses to improper, unaccepted, messages sent by this `StompMessageHandler`.
|
||||
|
||||
The `StompReceiptEvent` s are emitted from the `StompMessageHandler` as a part of `StompSession.Receiptable`
|
||||
callbacks in the asynchronous answers for the sent messages to the `StompSession`.
|
||||
The `StompReceiptEvent` can be positive and negative depending on whether or not the `RECEIPT` frame was received
|
||||
from the server within the `receiptTimeLimit` period, which can be configured on the `StompClientSupport` instance.
|
||||
Defaults to `15 * 1000`.
|
||||
|
||||
NOTE: The `StompSession.Receiptable` callbacks are added only if the `RECEIPT` STOMP header of the message to send
|
||||
is not `null`.
|
||||
Automatic `RECEIPT` header generation can be enabled on the `StompSession` through its `autoReceipt` option and
|
||||
on the `StompSessionManager` respectively.
|
||||
|
||||
See the next paragraph for more information how to configure Spring Integration to accept those `ApplicationEvent` s.
|
||||
|
||||
[[stomp-java-config]]
|
||||
=== STOMP Adapters Java Configuration
|
||||
|
||||
A comprehensive Java & Annotation Configuration for STOMP Adapters may look like this:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Configuration
|
||||
@EnableIntegration
|
||||
public class StompConfiguration {
|
||||
|
||||
@Bean
|
||||
public Reactor2TcpStompClient stompClient() {
|
||||
Reactor2TcpStompClient stompClient = new Reactor2TcpStompClient("127.0.0.1", 61613);
|
||||
stompClient.setMessageConverter(new PassThruMessageConverter());
|
||||
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
|
||||
taskScheduler.afterPropertiesSet();
|
||||
stompClient.setTaskScheduler(taskScheduler);
|
||||
stompClient.setReceiptTimeLimit(5000);
|
||||
return stompClient;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public StompSessionManager stompSessionManager() {
|
||||
Reactor2TcpStompSessionManager stompSessionManager = new Reactor2TcpStompSessionManager(stompClient());
|
||||
stompSessionManager.setAutoReceipt(true);
|
||||
return stompSessionManager;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PollableChannel stompInputChannel() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public StompInboundChannelAdapter stompInboundChannelAdapter() {
|
||||
StompInboundChannelAdapter adapter =
|
||||
new StompInboundChannelAdapter(stompSessionManager(), "/topic/myTopic");
|
||||
adapter.setOutputChannel(stompInputChannel());
|
||||
return adapter;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ServiceActivator(inputChannel = "stompOutputChannel")
|
||||
public MessageHandler stompMessageHandler() {
|
||||
StompMessageHandler handler = new StompMessageHandler(stompSessionManager());
|
||||
handler.setDestination("/topic/myTopic");
|
||||
return handler;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PollableChannel stompEvents() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ApplicationListener<ApplicationEvent> stompEventListener() {
|
||||
ApplicationEventListeningMessageProducer producer = new ApplicationEventListeningMessageProducer();
|
||||
producer.setEventTypes(StompIntegrationEvent.class);
|
||||
producer.setOutputChannel(stompEvents());
|
||||
return producer;
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
[[stomp-namespace]]
|
||||
=== STOMP Namespace Support
|
||||
|
||||
Spring Integration _STOMP_ namespace implements the _inbound_ and _outbound_ channel adapter components described below.
|
||||
To include it in your configuration, simply provide the following namespace declaration in your application context
|
||||
configuration file:
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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:int-stomp="http://www.springframework.org/schema/integration/stomp"
|
||||
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">
|
||||
...
|
||||
</beans>
|
||||
----
|
||||
|
||||
*<int-stomp:outbound-channel-adapter>*
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<int-stomp:outbound-channel-adapter
|
||||
id="" <1>
|
||||
channel="" <2>
|
||||
stomp-session-manager="" <3>
|
||||
header-mapper="" <4>
|
||||
mapped-headers="" <5>
|
||||
destination="" <6>
|
||||
destination-expression="" <7>
|
||||
auto-startup="" <8>
|
||||
phase=""/> <9>
|
||||
----
|
||||
|
||||
|
||||
|
||||
<1> The component bean name.
|
||||
The `MessageHandler` is registered with the bean alias `id + '.handler'`.
|
||||
If the `channel` attribute isn't provided, a `DirectChannel` is created and registered with the application context
|
||||
with this `id` attribute as the bean name.
|
||||
In this case, the endpoint is registered with the bean name `id + '.adapter'`.
|
||||
|
||||
|
||||
<2> Identifies the channel attached to this adapter.
|
||||
_Optional_ - if `id` is present - see `id`.
|
||||
|
||||
|
||||
<3> Reference to a `StompSessionManager` bean, which encapsulates the low-level connection and `StompSession`
|
||||
handling operations.
|
||||
_Required_.
|
||||
|
||||
|
||||
<4> Reference to a bean implementing `HeaderMapper<StompHeaders>` that maps Spring Integration MessageHeaders to/from
|
||||
STOMP frame headers.
|
||||
This is mutually exclusive with `mapped-headers`.
|
||||
Defaults to `StompHeaderMapper`.
|
||||
|
||||
|
||||
<5> Comma-separated list of names of STOMP Headers to be mapped to the STOMP frame headers.
|
||||
This can only be provided if the `header-mapper` reference is not set.
|
||||
The values in this list can also be simple patterns to be matched against the header names (e.g. "foo*" or "*foo").
|
||||
A special token `STOMP_OUTBOUND_HEADERS` represents all the standard STOMP headers
|
||||
(content-length, receipt, heart-beat etc); they are included by default.
|
||||
If you wish to add your own headers, you must also include this token if you wish the standard headers to also be
|
||||
mapped or provide your own `HeaderMapper` implementation using `header-mapper`.
|
||||
|
||||
|
||||
<6> Name of the destination to which STOMP Messages will be sent.
|
||||
Mutually exclusive with the `destination-expression`.
|
||||
|
||||
|
||||
<7> A SpEL expression to be evaluated at runtime against each Spring Integration `Message` as the root object.
|
||||
Mutually exclusive with the `destination`.
|
||||
|
||||
|
||||
<8> Boolean value indicating whether this endpoint should start automatically.
|
||||
Default to `true`.
|
||||
|
||||
|
||||
<9> The lifecycle phase within which this endpoint should start and stop.
|
||||
The lower the value the earlier this endpoint will start and the later it will stop.
|
||||
The default is `Integer.MIN_VALUE`.
|
||||
Values can be negative.
|
||||
See `SmartLifeCycle`.
|
||||
|
||||
*<int-stomp:inbound-channel-adapter>*
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<int-stomp:inbound-channel-adapter
|
||||
id="" <1>
|
||||
channel="" <2>
|
||||
error-channel="" <3>
|
||||
stomp-session-manager="" <4>
|
||||
header-mapper="" <5>
|
||||
mapped-headers="" <6>
|
||||
destinations="" <7>
|
||||
send-timeout="" <8>
|
||||
payload-type="" <9>
|
||||
auto-startup="" <10>
|
||||
phase=""/> <11>
|
||||
----
|
||||
|
||||
|
||||
|
||||
<1> The component bean name.
|
||||
If the `channel` attribute isn't provided, a `DirectChannel` is created and registered with the application context
|
||||
with this `id` attribute as the bean name.
|
||||
In this case, the endpoint is registered with the bean name `id + '.adapter'`.
|
||||
|
||||
|
||||
<2> Identifies the channel attached to this adapter.
|
||||
|
||||
|
||||
<3> The `MessageChannel` bean reference to which the `ErrorMessages` should be sent.
|
||||
|
||||
|
||||
<4> See the same option on the `<int-stomp:outbound-channel-adapter>`.
|
||||
|
||||
|
||||
<5> Comma-separated list of names of STOMP Headers to be mapped from the STOMP frame headers.
|
||||
This can only be provided if the `header-mapper` reference is not set.
|
||||
The values in this list can also be simple patterns to be matched against the header names (e.g. "foo*" or "*foo").
|
||||
A special token `STOMP_INBOUND_HEADERS` represents all the standard STOMP headers
|
||||
(content-length, receipt, heart-beat etc); they are included by default.
|
||||
If you wish to add your own headers, you must also include this token if you wish the standard headers to also be
|
||||
mapped or provide your own `HeaderMapper` implementation using `header-mapper`.
|
||||
|
||||
|
||||
<6> See the same option on the `<int-stomp:outbound-channel-adapter>`.
|
||||
|
||||
|
||||
<7> Comma-separated list of STOMP destination names to subscribe.
|
||||
The list of destinations (and therefore subscriptions) can be modified at runtime
|
||||
through the `addDestination() and `removeDestination()` `@ManagedOperation` s.
|
||||
|
||||
|
||||
<8> Maximum amount of time in milliseconds to wait when sending a message to the channel if the channel may block.
|
||||
For example, a `QueueChannel` can block until space is available if its maximum capacity has been reached.
|
||||
|
||||
|
||||
<9> Fully qualified name of the java type for the target `payload` to convert from the incoming STOMP Frame.
|
||||
Default to `String.class`.
|
||||
|
||||
|
||||
<10> See the same option on the `<int-stomp:outbound-channel-adapter>`.
|
||||
|
||||
|
||||
<11> See the same option on the `<int-stomp:outbound-channel-adapter>`.
|
||||
@@ -88,7 +88,7 @@ If `useBroker = false` and received message is of `SimpMessageType.CONNECT` type
|
||||
|
||||
NOTE: Spring's WebSocket Support allows the configuration of only one Broker Relay, hence we don't require an `AbstractBrokerMessageHandler` reference, it is detected in the Application Context.
|
||||
|
||||
For more configuration option see <<web-sockets-namespace>>.
|
||||
For more configuration options see <<web-sockets-namespace>>.
|
||||
|
||||
[[web-socket-outbound-adapter]]
|
||||
=== WebSocket Outbound Channel Adapter
|
||||
@@ -100,7 +100,7 @@ On the client side, the `WebSocketSession` `id` message header isn't required, b
|
||||
To use the STOMP sub-protocol, this adapter should be configured with a `StompSubProtocolHandler`.
|
||||
Then you can send any STOMP message type to this adapter, using `StompHeaderAccessor.create(StompCommand...)` and a `MessageBuilder`, or just using a `HeaderEnricher` (see <<header-enricher>>).
|
||||
|
||||
For more configuration option see below.
|
||||
For more configuration options see below.
|
||||
|
||||
[[web-sockets-namespace]]
|
||||
=== WebSockets Namespace Support
|
||||
@@ -310,9 +310,10 @@ By default `Jackson2SockJsMessageCodec` is used requiring the Jackson library to
|
||||
|
||||
|
||||
<1> The component bean name.
|
||||
If the `channel` attribute isn't provided, a `DirectChannel` is created and registered with the application context with this `id` attribute as the bean name.
|
||||
If the `channel` attribute isn't provided, a `DirectChannel` is created and registered with the application context
|
||||
with this `id` attribute as the bean name.
|
||||
In this case, the endpoint is registered with the bean name `id + '.adapter'`.
|
||||
And the `MessageHandler` is registered with the bean alias `id +'.adapter'`.
|
||||
And the `MessageHandler` is registered with the bean alias `id + '.handler'`.
|
||||
|
||||
|
||||
<2> Identifies the channel attached to this adapter.
|
||||
|
||||
@@ -62,6 +62,12 @@ occurs.
|
||||
|
||||
See <<barrier>> for more information.
|
||||
|
||||
[[x4.2-stomp]]
|
||||
==== STOMP Support
|
||||
|
||||
STOMP support has been added to the framework as _inbound_ and _outbound_ channel adapters pair.
|
||||
See <<stomp>> for more information.
|
||||
|
||||
[[x4.2-general]]
|
||||
=== General Changes
|
||||
|
||||
|
||||
Reference in New Issue
Block a user