The BufferingStompDecoder now decorates rather than extend
StompDecoder. This allows a single StompDecoder instance to be
configured and extended independantly while buffering remains a
separate concern.
Mutate rather than re-create headers when decoding STOMP messages
before a message is sent on a message channel.
Use MessageBuilder.createMessage to ensure the fully prepared
MessageHeaders is used directly MessageHeaderAccessor instance.
Issue: SPR-11468
Refine semantics of ID and TIMESTAMP headers provided to protected
MessageHeaders constructor.
Refactor internal implementation of MessageHeaderAccessor.
Support mutating headers from a single thread while a message is being
built (e.g. StompDecoder creating message + then adding session id).
Improve immutablity in NativeMessageHeaderAccessor and in
StompHeaderAccessor.
Optimize object creation for initializing messages and subsequent
accessing their headers.
Introduce MessageHeaderAccessorFactory support to enable applying a
common strategies for ID and TIMESTAMP generation to every message.
Add MessageBuilder shortcut factory method for creating messages from
payload and a full-prepared MessageHeaders instance. Also add
equivalent constructors to GenericMessage and ErrorMessage.
Issue: SPR-11468
The UserDestinationMessageHandler adds a header providing a hint for
what the original destination a user may have used when subscribing.
That is then used when writing messages back to WebSocket clients to
ensure they dont see the internally used, transformed user destination.
This change moves the header name constatn to make it more broadly
applicable. For example SPR-11645.
Prior to this commit, @SubscribeMapping mapped methods (backed with
@SendTo* annotations, or not) would send MESSAGEs with the wrong
destination. Instead of using the original SUBSCRIBE destination, it
would use the lookup path computed from the configured prefixes in the
application.
This commit fixes this issue - now @SubscribeMapping MESSAGEs use the
original SUBSCRIBE destination.
Issue: SPR-11648
Update some native WebSocket session getters to return basic
information after it is closed. It is required for example in
SubProtocolWebSocketHandler#afterConnectionEstablished() or
StompSubProtocolHandler#afterSessionStarted().
Issue: SPR-11621
Proactively notify all active WebSocket sessions when a shutdown is
progress. Sessions then can ignore further attempts to send messages
and also stop stop trying to flush messages right away.
BufferingStompDecoder message buffer size limit can now be configured
with JavaConfig MessageBrokerRegistry.setMessageBufferSizeLimit() or
with XML <websocket:message-brocker message-buffer-size="">.
Issue: SPR-11527
Before this change the StompDecoder decoded and returned only the first
Message in the ByteBuffer passed to it. So to obtain all messages from
the buffer, one had to loop passing the same buffer in until no more
complete STOMP frames could be decoded.
This chage modifies StompDecoder to return List<Message> after
exhaustively decoding all available STOMP frames from the input buffer.
Also an overloaded decode method allows passing in Map that will be
populated with any headers successfully parsed, which is useful for
"peeking" at the "content-length" header.
This change also adds a BufferingStompDecoder sub-class which buffers
any content left in the input buffer after parsing one or more STOMP
frames. This sub-class can also deal with fragmented messages,
re-assembling them and parsing as a whole message.
Issue: SPR-11527
When a send timeout is detected, the WebSocket session is now closed
with a custom close status that indicates so. This allows skipping
parts of the close logic that may cause further hanging.
Issue: SPR-11450
Before this change SockJsSession implementations of WebSocketSession
used synchronization around its method implementations protecting
internal state and ensuring only a single thread is sending messages
at a time.
A WebSocketSession is generally expected to be used from one thread
at a time and now that application messages are sent through
ConcurrentWebSocketSessionDecorator, there is no concern about
application messages sent from the different threads.
While there are some remaining concerns, those can be addressed
without using the synchronized keyword. This change removes it from
the methods of all SockJS session implementations.
Issue: SPR-11450
Before this change the decorator ensured that for a specific WebSocket
session only one thread at a time can send a message. Other threads
attempting to send would have their messages buffered and each time
that occurs, a check is also made to see if the buffer limit has been
reached or the send time limit has been exceeded and if so the session
is closed.
This change adds further protection to ensure only one thread at a time
can perform the session limit checks and attempt to close the session.
Furthermore if the session has timed out and become unresponsive,
attempts to close it may block yet another thread. Taking this into
consideration this change also ensures that state associated with the
session is cleaned first before an attempt is made to close the session.
Issue: SPR-11450
Since we now wrap the WebSocketSession with a concurrent decorator, the
synchronized keyword around message sending needed to be removed.
Issue: SPR-11586
Prior to this commit, configuring a custom handshakeHandler when setting
up a stomp-endpoint with SockJS would not be taken into account:
<websocket:stomp-endpoint path="/foo">
<websocket:handshake-handler ref="customHandler"/>
<websocket:sockjs/>
</websocket:stomp-endpoint>
This commit fixes this by creating and registering a
WebsocketTransportHandler (with this handshakeHandler) as a
transportHandler override for the SockJSService.
Issue: SPR-11568
Prior to this commit, the codebase was using a mix of log4j.xml
and log4j.properties for test-related logging configuration. This
can be an issue as log4j takes the xml variant first when looking
for a default bootstrap configuration.
In practice, some modules declaring the properties variant were
taking the xml variant configuration from another module.
The general structure of the configuration has also been
harmonized to provide a standard console output as well as an
easy way to enable trace logs for the current module.
The clientInboundChannel and clientOutboundChannel now use twice
the number of available processors by default to accomodate for some
degree of blocking in task execution on average.
In practice these settings still need to be configured explicitly in
applications but these should serve as better default values than
the default values in ThreadPoolTaskExecutor.
Issue: SPR-11450
This change exposes the WebSocketSession attributes through a message header.
The StompSubProtocolHandler adds this to incoming messages.
For now messaging handling methods can access the map via @Header, e.g.:
@Header(StompHeaderAccessor.SESSION_ATTRIBUTES) Map<String, Object> attrs) {
Issue: SPR-11566
Add accessor for brokerAvailable in AbstractBrokerMessageHandler
Ensure brokerAvailable is set even if eventPublisher is not
Add tests BrokerMessageHandlerTests
Turn off brokerAvailable when StompBrokerRelayMessageHandler stops
Actually stop message handling when brokerAvailable=false
Improve log messages
Issue: SPR-11563
Prior to this commit, the `relay-port` attribute of the
`<websocket:stomp-broker-relay />` tag was of type `xsd:int`.
This prevents developers from using `PropertyPlaceholderConfigurer`,
even though this configuration key is a good candidate for such use
(this value depends on prod/staging/etc environment).
This commit changes that type to `xsd:string`.
Issue: SPR-11537
After this change, AbstractSockJsService does not add CORS headers if
the response already contains an "Access-Control-Allow-Origin" header.
Essentially it backs off assuming CORS headers are handled centrally
e.g. through a Filter.
In order to support this, the ServletServerHttpResponse now returns an
instance of HttpHeaders that also provides access to headers already
present in the HttpServletResponse.
Issue: SPR-11443