diff --git a/spring-integration-websocket/src/main/java/org/springframework/integration/websocket/IntegrationWebSocketContainer.java b/spring-integration-websocket/src/main/java/org/springframework/integration/websocket/IntegrationWebSocketContainer.java
index ac814fe94d..ff31a37e64 100644
--- a/spring-integration-websocket/src/main/java/org/springframework/integration/websocket/IntegrationWebSocketContainer.java
+++ b/spring-integration-websocket/src/main/java/org/springframework/integration/websocket/IntegrationWebSocketContainer.java
@@ -26,9 +26,6 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.DisposableBean;
-import org.springframework.context.ApplicationEvent;
-import org.springframework.context.ApplicationEventPublisher;
-import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.util.Assert;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.SubProtocolCapable;
@@ -36,7 +33,6 @@ import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.ConcurrentWebSocketSessionDecorator;
-import org.springframework.web.socket.messaging.SessionDisconnectEvent;
/**
* The high-level 'connection factory pattern' contract over low-level Web-Socket
@@ -59,7 +55,7 @@ import org.springframework.web.socket.messaging.SessionDisconnectEvent;
* @see org.springframework.integration.websocket.inbound.WebSocketInboundChannelAdapter
* @see org.springframework.integration.websocket.outbound.WebSocketOutboundMessageHandler
*/
-public abstract class IntegrationWebSocketContainer implements ApplicationEventPublisherAware, DisposableBean {
+public abstract class IntegrationWebSocketContainer implements DisposableBean {
protected final Log logger = LogFactory.getLog(this.getClass());
@@ -75,8 +71,6 @@ public abstract class IntegrationWebSocketContainer implements ApplicationEventP
private volatile int sendBufferSizeLimit = 512 * 1024;
- private ApplicationEventPublisher eventPublisher;
-
public void setSendTimeLimit(int sendTimeLimit) {
this.sendTimeLimit = sendTimeLimit;
}
@@ -85,11 +79,6 @@ public abstract class IntegrationWebSocketContainer implements ApplicationEventP
this.sendBufferSizeLimit = sendBufferSizeLimit;
}
- @Override
- public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
- this.eventPublisher = applicationEventPublisher;
- }
-
public void setMessageListener(WebSocketListener messageListener) {
Assert.state(this.messageListener == null || this.messageListener == messageListener,
"'messageListener' is already configured");
@@ -146,15 +135,6 @@ public abstract class IntegrationWebSocketContainer implements ApplicationEventP
this.sessions.clear();
}
- private void publishEvent(ApplicationEvent event) {
- try {
- this.eventPublisher.publishEvent(event);
- }
- catch (Throwable ex) {
- logger.error("Error while publishing " + event, ex);
- }
- }
-
/**
* An internal {@link WebSocketHandler} implementation to be used with native
* Web-Socket containers.
@@ -192,9 +172,6 @@ public abstract class IntegrationWebSocketContainer implements ApplicationEventP
if (IntegrationWebSocketContainer.this.messageListener != null) {
IntegrationWebSocketContainer.this.messageListener.afterSessionEnded(session, closeStatus);
}
- else if (IntegrationWebSocketContainer.this.eventPublisher != null) {
- publishEvent(new SessionDisconnectEvent(this, session.getId(), closeStatus));
- }
}
}
@@ -203,10 +180,8 @@ public abstract class IntegrationWebSocketContainer implements ApplicationEventP
WebSocketSession removed = IntegrationWebSocketContainer.this.sessions.remove(session.getId());
if (removed != null) {
IntegrationWebSocketContainer.this.sessions.remove(session.getId());
- if (IntegrationWebSocketContainer.this.eventPublisher != null) {
- publishEvent(new SessionErrorEvent(this, session.getId(), exception));
- }
}
+ throw new Exception(exception);
}
@Override
diff --git a/spring-integration-websocket/src/main/java/org/springframework/integration/websocket/SessionErrorEvent.java b/spring-integration-websocket/src/main/java/org/springframework/integration/websocket/SessionErrorEvent.java
deleted file mode 100644
index 1fd6a5b329..0000000000
--- a/spring-integration-websocket/src/main/java/org/springframework/integration/websocket/SessionErrorEvent.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.websocket;
-
-import org.springframework.context.ApplicationEvent;
-import org.springframework.util.Assert;
-
-/**
- * The {@link ApplicationEvent} implementation to represent the
- * {@link org.springframework.web.socket.WebSocketSession} errors.
- *
- * @author Artem Bilan
- * @since 4.1
- */
-@SuppressWarnings("serial")
-public class SessionErrorEvent extends ApplicationEvent {
-
- private final String sessionId;
-
- private final Throwable exception;
-
-
- /**
- * Create a new {@link ApplicationEvent} represented the error on the session.
- * @param source the component that published the event (never {@code null})
- * @param sessionId the id of the session
- * @param exception the exception on the session
- */
- public SessionErrorEvent(Object source, String sessionId, Throwable exception) {
- super(source);
- Assert.notNull(sessionId, "'sessionId' must not be null");
- this.sessionId = sessionId;
- this.exception = exception;
- }
-
- /**
- * Return the session id.
- * @return the sessionId
- */
- public String getSessionId() {
- return this.sessionId;
- }
-
- /**
- * Return the exception for the session id.
- * @return the exception
- */
- public Throwable getException() {
- return exception;
- }
-
- @Override
- public String toString() {
- return "SessionErrorEvent: sessionId=" + this.sessionId;
- }
-
-}
diff --git a/spring-integration-websocket/src/main/resources/org/springframework/integration/websocket/config/spring-integration-websocket-4.1.xsd b/spring-integration-websocket/src/main/resources/org/springframework/integration/websocket/config/spring-integration-websocket-4.1.xsd
index ff79e5954c..126bd4b2d7 100644
--- a/spring-integration-websocket/src/main/resources/org/springframework/integration/websocket/config/spring-integration-websocket-4.1.xsd
+++ b/spring-integration-websocket/src/main/resources/org/springframework/integration/websocket/config/spring-integration-websocket-4.1.xsd
@@ -234,7 +234,8 @@
-
+
@@ -357,7 +358,7 @@
- Fully qualified name of the java type for the target `payload`
+ Fully qualified name of the java type for the target 'payload'
to convert from the incoming WebSocketMessage.
@@ -365,11 +366,10 @@
- Flag to indicate if this adapter will send non-MESSAGE type WebSocketMessages
- and messages with broker destinations to the `AbstractBrokerMessageHandler`
+ Flag to indicate if this adapter will send non-MESSAGE type 'WebSocketMessage's
+ and messages with broker destinations to the 'AbstractBrokerMessageHandler'
from the application context.
- If the `AbstractBrokerMessageHandler` bean isn't present the warn log is emitted
- and adapter behaviour is falling back to default like this attribute is 'false'.
+ The 'Broker Relay' configuration is required when 'use-broker' is 'true'.
This attribute is used only on server side. On client side it is ignored.
Defaults to 'false'.
@@ -441,7 +441,7 @@
Flag to indicate if the default converters should be registered after any custom
- converters. This flag is used only if message-converters
+ converters. This flag is used only if 'message-converters'
are provided, otherwise all default converters will be registered.
Defaults to 'false'.
diff --git a/src/reference/docbook/aggregator.xml b/src/reference/docbook/aggregator.xml
index 787199e422..242c5f1422 100644
--- a/src/reference/docbook/aggregator.xml
+++ b/src/reference/docbook/aggregator.xml
@@ -882,8 +882,7 @@ then you should simply provide an implementation of the ReleaseStrate
- Managing State in an Aggregator:
- MessageGroupStore
+ Managing State in an Aggregator: MessageGroupStore
Aggregator (and some other patterns in Spring Integration) is a
stateful pattern that requires decisions to be made based on a group of
diff --git a/src/reference/docbook/index.xml b/src/reference/docbook/index.xml
index dca7fcea06..d6adcd4a02 100644
--- a/src/reference/docbook/index.xml
+++ b/src/reference/docbook/index.xml
@@ -144,6 +144,7 @@
+
diff --git a/src/reference/docbook/web-sockets.xml b/src/reference/docbook/web-sockets.xml
new file mode 100644
index 0000000000..5afe4bb4cc
--- /dev/null
+++ b/src/reference/docbook/web-sockets.xml
@@ -0,0 +1,615 @@
+
+
+ WebSockets Support
+
+
+ Introduction
+
+ Starting with version 4.1 Spring Integration has introduced
+ WebSocket support. It is based on architecture, infrastructure and API
+ from the Spring Framework's web-socket module. Therefore, many of Spring WebSocket's
+ components (e.g. SubProtocolHandler or
+ WebSocketClient) and configuration options (e.g.
+ @EnableWebSocketMessageBroker) can be reused within Spring Integration.
+ For more information, please, refer to the
+ Spring Framework WebSocket Support chapter in the Spring Framework reference manual.
+
+
+ Since the Spring Framework WebSocket infrastructure is based on the Spring Messaging
+ foundation and provides a basic Messaging framework based on the same
+ MessageChannels, MessageHandlers
+ that Spring Integration uses,
+ and some POJO-method annotation mappings, Spring Integration can be directly involved in a
+ WebSocket flow, even without WebSocket adapters. For this purpose you can simply configure a
+ Spring Integration @MessagingGateway with appropriate annotations:
+
+
+
+
+
+ Overview
+
+ Since the WebSocket protocol is streaming by definition and we can
+ send and receive messages to/from a WebSocket at the same time,
+ we can simply deal with an appropriate WebSocketSession,
+ regardless of being on the client or server side. To encapsulate the connection management and
+ WebSocketSession registry, the IntegrationWebSocketContainer
+ is provided with ClientWebSocketContainer and ServerWebSocketContainer
+ implementations. Thanks to the WebSocket API
+ and its implementation in the Spring Framework, with many extensions, the same classes are used on the server
+ side as well as the client side (from a Java perspective, of course). Hence most connection and
+ WebSocketSession registry options are the same on both sides. That allows us
+ to reuse many configuration items and infrastructure hooks to build WebSocket applications on the server
+ side as well as on the client side:
+ singletonList(new WebSocketTransport(new JettyWebSocketClient())));
+}
+
+@Bean
+public IntegrationWebSocketContainer clientWebSocketContainer() {
+ return new ClientWebSocketContainer(webSocketClient(), "ws://my.server.com/endpoint");
+}
+
+//Server side
+@Bean
+public IntegrationWebSocketContainer serverWebSocketContainer() {
+ return new ServerWebSocketContainer("/endpoint").withSockJs();
+}]]>
+
+
+ The IntegrationWebSocketContainer is designed to achieve
+ bidirectional messaging and can be shared between Inbound and Outbound
+ Channel Adapters (see below), can be referenced only from one of them (when using
+ one-way - sending or receiving - WebSocket messaging). It can be used without any Channel
+ Adapter, but in this case, IntegrationWebSocketContainer only plays a role
+ as the WebSocketSession registry.
+
+
+ The ServerWebSocketContainer implements WebSocketConfigurer
+ to register an internal IntegrationWebSocketContainer.IntegrationWebSocketHandler
+ as an Endpoint under the provided paths and other server WebSocket options (such as
+ HandshakeHandler or SockJS fallback) within the
+ ServletWebSocketHandlerRegistry for the target vendor WebSocket Container. This
+ registration is achieved with an infrastructural WebSocketIntegrationConfigurationInitializer
+ component, which does the same as the @EnableWebSocket annotation. This means that
+ using just @EnableIntegration (or any Spring Integration Namespace in the
+ application context)
+ you can omit the @EnableWebSocket declaration, because all WebSocket
+ Endpoints are detected by the Spring Integration infrastructure.
+
+
+
+
+ WebSocket Inbound Channel Adapter
+
+ The WebSocketInboundChannelAdapter implements the receiving part of
+ WebSocketSession interaction. It must be supplied with a
+ IntegrationWebSocketContainer, and the adapter registers itself as a
+ WebSocketListener to handle incoming messages and
+ WebSocketSession events.
+
+
+ Only one WebSocketListener can be registered in the
+ IntegrationWebSocketContainer.
+
+
+ For WebSocket sub-protocols, the
+ WebSocketInboundChannelAdapter can be configured with
+ SubProtocolHandlerRegistry as the second constructor argument. The adapter delegates
+ to the SubProtocolHandlerRegistry to determine the appropriate
+ SubProtocolHandler for the accepted WebSocketSession
+ and to convert WebSocketMessage to a Message
+ according to the sub-protocol implementation.
+
+
+ By default, the WebSocketInboundChannelAdapter relies just only on the raw
+ PassThruSubProtocolHandler implementation, which simply converts the
+ WebSocketMessage to a Message.
+
+
+ The WebSocketInboundChannelAdapter accepts and sends to the underlying integration
+ flow only Messages with SimpMessageType.MESSAGE or an empty
+ simpMessageType header. All other Message types are handled
+ through the ApplicationEvents emitted from a
+ SubProtocolHandler implementation (e.g.
+ StompSubProtocolHandler).
+
+
+ On the server side WebSocketInboundChannelAdapter can be configured with the
+ useBroker = true option, if the @EnableWebSocketMessageBroker
+ configuration is present. In this case all non-MESSAGE Message
+ types are delegated to the provided AbstractBrokerMessageHandler. In addition, if the
+ Broker Relay is configured with destination prefixes, those Messages, which match to the Broker
+ destinations, are routed to the AbstractBrokerMessageHandler, instead of to the
+ outputChannel of the WebSocketInboundChannelAdapter.
+
+
+ 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 .
+
+
+
+
+ WebSocket Outbound Channel Adapter
+
+ The WebSocketOutboundChannelAdapter accepts Spring Integration messages from its
+ MessageChannel, determines the
+ WebSocketSession id from the MessageHeaders,
+ retrieves the WebSocketSession from the provided
+ IntegrationWebSocketContainer and delegates the conversion and sending
+ WebSocketMessage work to the appropriate
+ SubProtocolHandler from the provided
+ SubProtocolHandlerRegistry.
+
+
+ On the client side, the WebSocketSession id message header isn't
+ required, because ClientWebSocketContainer deals only with a single connection and
+ its WebSocketSession respectively.
+
+
+ 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
+ ).
+
+
+ For more configuration option see below.
+
+
+
+
+ WebSockets Namespace Support
+
+ Spring Integration WebSocket namespace includes several components described below.
+ To include it in your configuration, simply provide the following namespace declaration in your
+ application context configuration file:
+
+
+
+
+ ...
+]]>
+
+ <int-websocket:client-container>
+
+ ]]>
+
+ ]]>]]>
+
+
+
+
+ The component bean name.
+
+
+
+
+ The WebSocketClient bean reference.
+
+
+
+
+ The uri or uriTemplate to the target WebSocket service. If it is used as
+ a uriTemplate with URI variable placeholders, the uri-variables
+ attribute is required.
+
+
+
+
+ Comma-separated values for the URI variable placeholders within the uri attribute
+ value. The values are replaced into the placeholders according
+ to the order in the uri. See UriComponents.expand(Object... uriVariableValues).
+
+
+
+
+ The Origin Handshake HTTP header value.
+
+
+
+
+ The WebSocket session 'send' timeout limit. Defaults to 10000.
+
+
+
+
+ The WebSocket session 'send' message size limit. Defaults to 524288.
+
+
+
+
+ Boolean value indicating whether this endpoint should start automatically.
+ Defaults to false, assuming that this container will be started from the
+ .
+
+
+
+
+ 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.MAX_VALUE. Values can be negative. See
+ SmartLifeCycle.
+
+
+
+
+
+
+
+ <int-websocket:server-container>
+
+ ]]> ]]>]]>
+
+
+
+
+ The component bean name.
+
+
+
+
+ A path (or comma-separated paths) that maps a particular request to a
+ WebSocketHandler.
+ Exact path mapping URIs (such as "/myPath") are supported as well
+ as ant-style path patterns (such as /myPath/**).
+
+
+
+
+ The HandshakeHandler bean reference.
+ Default to DefaultHandshakeHandler.
+
+
+
+
+ List of HandshakeInterceptor bean references.
+
+
+
+
+ See the same option on the <int-websocket:client-container>.
+
+
+
+
+ See the same option on the <int-websocket:client-container>.
+
+
+
+
+ Transports with no native cross-domain communication (e.g. "eventsource",
+ "htmlfile") must get a simple page from the "foreign" domain in an invisible
+ iframe so that code in the iframe can run from a domain local to the SockJS
+ server. Since the iframe needs to load the SockJS javascript client library,
+ this property allows specifying where to load it from.
+
+ By default this is set to point to
+ https://d1fxtkz8shb9d2.cloudfront.net/sockjs-0.3.4.min.js. However it can
+ also be set to point to a URL served by the application.
+
+ Note that it's possible to specify a relative URL in which case the URL
+ must be relative to the iframe URL. For example assuming a SockJS endpoint
+ mapped to "/sockjs", and resulting iframe URL "/sockjs/iframe.html", then the
+ The relative URL must start with "../../" to traverse up to the location
+ above the SockJS mapping. In case of a prefix-based Servlet mapping one more
+ traversal may be needed.
+
+
+
+
+ Minimum number of bytes that can be send over a single HTTP streaming request before
+ it will be closed. Defaults to 128K (i.e. 128*1024 bytes).
+
+
+
+
+ The "cookie_needed" value in the response from the SockJs "/info" endpoint.
+ This property indicates whether the use of a JSESSIONID cookie is required for the
+ application to function correctly, e.g. for load balancing or in Java Servlet containers for
+ the use of an HTTP session.
+
+
+
+
+ The amount of time in milliseconds when the server has not sent any messages and
+ after which the server should send a heartbeat frame to the client in order to keep the
+ connection from breaking. The default value is 25,000 (25 seconds).
+
+
+
+
+ The amount of time in milliseconds before a client is considered disconnected after
+ not having a receiving connection, i.e. an active connection over which the server can send
+ data to the client. The default value is 5000.
+
+
+
+
+ The number of server-to-client messages that a session can cache while waiting for
+ the next HTTP polling request from the client.
+ The default size is 100.
+
+
+
+
+ Some load balancers don't support websockets. Set this option to false to disable
+ the WebSocket transport on the server side. The default value is true.
+
+
+
+
+ The TaskScheduler bean reference; a new
+ ThreadPoolTaskScheduler instance will be
+ created if no value is provided. This scheduler instance will be used for scheduling
+ heart-beat messages.
+
+
+
+
+ The SockJsMessageCodec bean reference to use for
+ encoding and decoding SockJS messages.
+ By default Jackson2SockJsMessageCodec is used requiring the
+ Jackson library to be present on the classpath.
+
+
+
+
+ List of TransportHandler bean references.
+
+
+
+
+
+
+ <int-websocket:outbound-channel-adapter>
+
+
+ ]]>
+
+
+
+ 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'. And the
+ MessageHandler is registered with the bean alias
+ id +'.adapter'.
+
+
+
+
+ Identifies the channel attached to this adapter.
+
+
+
+
+ The reference to the IntegrationWebSocketContainer bean,
+ which encapsulates the low-level connection and WebSocketSession handling operations. Required.
+
+
+
+
+ Optional reference to a SubProtocolHandler instance.
+ It is used when the client did not request a sub-protocol or it is a single protocol-handler.
+ If this reference or protocol-handlers list aren't provided the
+ PassThruSubProtocolHandler is used by default.
+
+
+
+
+ List of SubProtocolHandler bean references
+ for this Channel Adapter. If only a single bean reference is provided and a
+ default-protocol-handler isn't provided, that single
+ SubProtocolHandler will be used as the
+ default-protocol-handler. If this attribute or
+ default-protocol-handler aren't provided, the
+ PassThruSubProtocolHandler is used by default.
+
+
+
+
+ List of MessageConverter bean references for this Channel
+ Adapter.
+
+
+
+
+ Flag to indicate if the default converters should be registered after any custom
+ converters. This flag is used only if message-converters
+ are provided, otherwise all default converters will be registered.
+ Defaults to false. The default converters are (in the order):
+ StringMessageConverter, ByteArrayMessageConverter
+ and MappingJackson2MessageConverter if the Jackson library is present on
+ the classpath.
+
+
+
+
+ Boolean value indicating whether this endpoint should start automatically.
+ Default to true.
+
+
+
+
+ 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-websocket:inbound-channel-adapter>
+
+
+ ]]>
+
+
+
+ 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'.
+
+
+
+
+ Identifies the channel attached to this adapter.
+
+
+
+
+ The MessageChannel bean reference to which
+ the ErrorMessages should be sent.
+
+
+
+
+ See the same option on the <int-websocket:outbound-channel-adapter>.
+
+
+
+
+ See the same option on the <int-websocket:outbound-channel-adapter>.
+
+
+
+
+ See the same option on the <int-websocket:outbound-channel-adapter>.
+
+
+
+
+ See the same option on the <int-websocket:outbound-channel-adapter>.
+
+
+
+
+ See the same option on the <int-websocket:outbound-channel-adapter>.
+
+
+
+
+ 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.
+
+
+
+
+ Fully qualified name of the java type for the target payload
+ to convert from the incoming WebSocketMessage.
+ Default to String.
+
+
+
+
+ Flag to indicate if this adapter will send non-MESSAGE
+ WebSocketMessages and messages with broker destinations to the
+ AbstractBrokerMessageHandler from the application context.
+ The Broker Relay configuration is required when this attribute is
+ true.
+ This attribute is used only on the server side. On the client side, it is ignored.
+ Defaults to false.
+
+
+
+
+ See the same option on the <int-websocket:outbound-channel-adapter>.
+
+
+
+
+ See the same option on the <int-websocket:outbound-channel-adapter>.
+
+
+
+
+
+
diff --git a/src/reference/docbook/whats-new.xml b/src/reference/docbook/whats-new.xml
index 2b9ac647c3..b906ffc559 100644
--- a/src/reference/docbook/whats-new.xml
+++ b/src/reference/docbook/whats-new.xml
@@ -18,13 +18,13 @@
See .
-
+
WebSocket support
The WebSocket module is now available. It is fully based on the Spring WebSocket
and Spring Messaging modules and provides an <inbound-channel-adapter> and an
<outbound-channel-adapter>.
- More documentation to follow.
+ See for more information.