23
23
import org .springframework .util .MultiValueMap ;
24
24
25
25
import java .nio .ByteBuffer ;
26
- import java .util .ArrayList ;
27
26
import java .util .Collections ;
28
27
import java .util .List ;
29
28
import java .util .Queue ;
32
31
33
32
/**
34
33
* An extension of {@link org.springframework.messaging.simp.stomp.StompDecoder}
35
- * that chunks any bytes remaining after a single full STOMP frame has been read.
36
- * The remaining bytes may contain more STOMP frames or an incomplete STOMP frame.
34
+ * that buffers content remaining in the input ByteBuffer after the parent
35
+ * class has read all (complete) STOMP frames from it. The remaining content
36
+ * represents an incomplete STOMP frame. When called repeatedly with additional
37
+ * data, the decode method returns one or more messages or, if there is not
38
+ * enough data still, continues to buffer.
37
39
*
38
- * <p>Similarly if there is not enough content for a full STOMP frame, the content
39
- * is buffered until more input is received. That means the
40
- * {@link #decode(java.nio.ByteBuffer)} effectively never returns {@code null} as
41
- * the parent class does.
40
+ * <p>A single instance of this decoder can be invoked repeatedly to read all
41
+ * messages from a single stream (e.g. WebSocket session) as long as decoding
42
+ * does not fail. If there is an exception, StompDecoder instance should not
43
+ * be used any more as its internal state is not guaranteed to be consistent.
44
+ * It is expected that the underlying session is closed at that point.
42
45
*
43
46
* @author Rossen Stoyanchev
44
47
* @since 4.0.3
@@ -58,10 +61,16 @@ public BufferingStompDecoder(int bufferSizeLimit) {
58
61
}
59
62
60
63
64
+ /**
65
+ * Return the configured buffer size limit.
66
+ */
61
67
public int getBufferSizeLimit () {
62
68
return this .bufferSizeLimit ;
63
69
}
64
70
71
+ /**
72
+ * Calculate the current buffer size.
73
+ */
65
74
public int getBufferSize () {
66
75
int size = 0 ;
67
76
for (ByteBuffer buffer : this .chunks ) {
@@ -70,29 +79,50 @@ public int getBufferSize() {
70
79
return size ;
71
80
}
72
81
82
+ /**
83
+ * Get the expected content length of the currently buffered, incomplete STOMP frame.
84
+ */
73
85
public Integer getExpectedContentLength () {
74
86
return this .expectedContentLength ;
75
87
}
76
88
77
89
90
+ /**
91
+ * Decodes one or more STOMP frames from the given {@code ByteBuffer} into a
92
+ * list of {@link Message}s.
93
+ *
94
+ * <p>If there was enough data to parse a "content-length" header, then the
95
+ * value is used to determine how much more data is needed before a new
96
+ * attempt to decode is made.
97
+ *
98
+ * <p>If there was not enough data to parse the "content-length", or if there
99
+ * is "content-length" header, every subsequent call to decode attempts to
100
+ * parse again with all available data. Therefore the presence of a "content-length"
101
+ * header helps to optimize the decoding of large messages.
102
+ *
103
+ * @param newBuffer a buffer containing new data to decode
104
+ *
105
+ * @return decoded messages or an empty list
106
+ * @throws StompConversionException raised in case of decoding issues
107
+ */
78
108
@ Override
79
- public List <Message <byte []>> decode (ByteBuffer newData ) {
109
+ public List <Message <byte []>> decode (ByteBuffer newBuffer ) {
80
110
81
- this .chunks .add (newData );
111
+ this .chunks .add (newBuffer );
82
112
83
113
checkBufferLimits ();
84
114
85
115
if (getExpectedContentLength () != null && getBufferSize () < this .expectedContentLength ) {
86
116
return Collections .<Message <byte []>>emptyList ();
87
117
}
88
118
89
- ByteBuffer buffer = assembleChunksAndReset ();
119
+ ByteBuffer bufferToDecode = assembleChunksAndReset ();
90
120
91
121
MultiValueMap <String , String > headers = new LinkedMultiValueMap <String , String >();
92
- List <Message <byte []>> messages = decode (buffer , headers );
122
+ List <Message <byte []>> messages = decode (bufferToDecode , headers );
93
123
94
- if (buffer .hasRemaining ()) {
95
- this .chunks .add (buffer );
124
+ if (bufferToDecode .hasRemaining ()) {
125
+ this .chunks .add (bufferToDecode );
96
126
this .expectedContentLength = getContentLength (headers );
97
127
}
98
128
0 commit comments