1616
1717package org .springframework .messaging .simp .stomp ;
1818
19-
2019import java .nio .ByteBuffer ;
2120import java .util .Collections ;
2221import java .util .List ;
2827import org .springframework .util .LinkedMultiValueMap ;
2928import org .springframework .util .MultiValueMap ;
3029
31-
3230/**
3331 * An extension of {@link org.springframework.messaging.simp.stomp.StompDecoder}
3432 * that buffers content remaining in the input ByteBuffer after the parent
4543 *
4644 * @author Rossen Stoyanchev
4745 * @since 4.0.3
46+ * @see StompDecoder
4847 */
4948public class BufferingStompDecoder {
5049
5150 private final StompDecoder stompDecoder ;
5251
5352 private final int bufferSizeLimit ;
5453
55- private final Queue <ByteBuffer > chunks = new LinkedBlockingQueue <>();
54+ private final Queue <ByteBuffer > chunks = new LinkedBlockingQueue <ByteBuffer >();
5655
5756 private volatile Integer expectedContentLength ;
5857
5958
59+ /**
60+ * Create a new {@code BufferingStompDecoder} wrapping the given {@code StompDecoder}.
61+ * @param stompDecoder the target decoder to wrap
62+ * @param bufferSizeLimit the buffer size limit
63+ */
6064 public BufferingStompDecoder (StompDecoder stompDecoder , int bufferSizeLimit ) {
61- Assert .notNull (stompDecoder , "'stompDecoder' is required" );
62- Assert .isTrue (bufferSizeLimit > 0 , "Buffer size must be greater than 0" );
65+ Assert .notNull (stompDecoder , "StompDecoder is required" );
66+ Assert .isTrue (bufferSizeLimit > 0 , "Buffer size limit must be greater than 0" );
6367 this .stompDecoder = stompDecoder ;
6468 this .bufferSizeLimit = bufferSizeLimit ;
6569 }
6670
6771
6872 /**
69- * Return the wrapped
70- * {@link org.springframework.messaging.simp.stomp.StompDecoder}.
73+ * Return the wrapped {@link StompDecoder}.
7174 */
72- public StompDecoder getStompDecoder () {
75+ public final StompDecoder getStompDecoder () {
7376 return this .stompDecoder ;
7477 }
7578
7679 /**
7780 * Return the configured buffer size limit.
7881 */
79- public int getBufferSizeLimit () {
82+ public final int getBufferSizeLimit () {
8083 return this .bufferSizeLimit ;
8184 }
8285
83- /**
84- * Calculate the current buffer size.
85- */
86- public int getBufferSize () {
87- int size = 0 ;
88- for (ByteBuffer buffer : this .chunks ) {
89- size = size + buffer .remaining ();
90- }
91- return size ;
92- }
93-
94- /**
95- * Get the expected content length of the currently buffered, incomplete STOMP frame.
96- */
97- public Integer getExpectedContentLength () {
98- return this .expectedContentLength ;
99- }
100-
10186
10287 /**
10388 * Decodes one or more STOMP frames from the given {@code ByteBuffer} into a
10489 * list of {@link Message}s.
105- *
10690 * <p>If there was enough data to parse a "content-length" header, then the
10791 * value is used to determine how much more data is needed before a new
10892 * attempt to decode is made.
109- *
11093 * <p>If there was not enough data to parse the "content-length", or if there
11194 * is "content-length" header, every subsequent call to decode attempts to
11295 * parse again with all available data. Therefore the presence of a "content-length"
11396 * header helps to optimize the decoding of large messages.
114- *
11597 * @param newBuffer a buffer containing new data to decode
116- *
11798 * @return decoded messages or an empty list
11899 * @throws StompConversionException raised in case of decoding issues
119100 */
120101 public List <Message <byte []>> decode (ByteBuffer newBuffer ) {
121-
122102 this .chunks .add (newBuffer );
123-
124103 checkBufferLimits ();
125104
126- if (getExpectedContentLength () != null && getBufferSize () < this .expectedContentLength ) {
127- return Collections .< Message < byte []>> emptyList ();
105+ if (this . expectedContentLength != null && getBufferSize () < this .expectedContentLength ) {
106+ return Collections .emptyList ();
128107 }
129108
130109 ByteBuffer bufferToDecode = assembleChunksAndReset ();
131-
132- MultiValueMap <String , String > headers = new LinkedMultiValueMap <>();
110+ MultiValueMap <String , String > headers = new LinkedMultiValueMap <String , String >();
133111 List <Message <byte []>> messages = this .stompDecoder .decode (bufferToDecode , headers );
134112
135113 if (bufferToDecode .hasRemaining ()) {
@@ -140,21 +118,6 @@ public List<Message<byte[]>> decode(ByteBuffer newBuffer) {
140118 return messages ;
141119 }
142120
143- private void checkBufferLimits () {
144- if (getExpectedContentLength () != null ) {
145- if (getExpectedContentLength () > getBufferSizeLimit ()) {
146- throw new StompConversionException (
147- "The 'content-length' header " + getExpectedContentLength () +
148- " exceeds the configured message buffer size limit " + getBufferSizeLimit ());
149- }
150- }
151- if (getBufferSize () > getBufferSizeLimit ()) {
152- throw new StompConversionException ("The configured stomp frame buffer size limit of " +
153- getBufferSizeLimit () + " bytes has been exceeded" );
154-
155- }
156- }
157-
158121 private ByteBuffer assembleChunksAndReset () {
159122 ByteBuffer result ;
160123 if (this .chunks .size () == 1 ) {
@@ -172,4 +135,36 @@ private ByteBuffer assembleChunksAndReset() {
172135 return result ;
173136 }
174137
138+ private void checkBufferLimits () {
139+ if (this .expectedContentLength != null ) {
140+ if (this .expectedContentLength > this .bufferSizeLimit ) {
141+ throw new StompConversionException (
142+ "STOMP 'content-length' header value " + this .expectedContentLength +
143+ " exceeds configured buffer size limit " + this .bufferSizeLimit );
144+ }
145+ }
146+ if (getBufferSize () > this .bufferSizeLimit ) {
147+ throw new StompConversionException ("The configured STOMP buffer size limit of " +
148+ this .bufferSizeLimit + " bytes has been exceeded" );
149+ }
150+ }
151+
152+ /**
153+ * Calculate the current buffer size.
154+ */
155+ public int getBufferSize () {
156+ int size = 0 ;
157+ for (ByteBuffer buffer : this .chunks ) {
158+ size = size + buffer .remaining ();
159+ }
160+ return size ;
161+ }
162+
163+ /**
164+ * Get the expected content length of the currently buffered, incomplete STOMP frame.
165+ */
166+ public Integer getExpectedContentLength () {
167+ return this .expectedContentLength ;
168+ }
169+
175170}
0 commit comments