21
21
import java .io .IOException ;
22
22
import java .nio .charset .StandardCharsets ;
23
23
import java .util .Collections ;
24
+ import java .util .LinkedHashMap ;
24
25
import java .util .List ;
25
26
import java .util .Map ;
26
27
import java .util .Map .Entry ;
@@ -50,6 +51,16 @@ public class StompEncoder {
50
51
51
52
private static final Log logger = LogFactory .getLog (StompEncoder .class );
52
53
54
+ private static final int HEADER_KEY_CACHE_LIMIT = 32 ;
55
+
56
+ @ SuppressWarnings ("serial" )
57
+ private final Map <String , byte []> headerKeyCache =
58
+ new LinkedHashMap <String , byte []>(HEADER_KEY_CACHE_LIMIT , 0.75f , true ) {
59
+ @ Override
60
+ protected boolean removeEldestEntry (Map .Entry <String , byte []> eldest ) {
61
+ return size () > HEADER_KEY_CACHE_LIMIT ;
62
+ }
63
+ };
53
64
54
65
/**
55
66
* Encodes the given STOMP {@code message} into a {@code byte[]}
@@ -130,11 +141,11 @@ private void writeHeaders(StompCommand command, Map<String, Object> headers, byt
130
141
values = Collections .singletonList (StompHeaderAccessor .getPasscode (headers ));
131
142
}
132
143
133
- byte [] encodedKey = encodeHeaderString (entry .getKey (), shouldEscape );
144
+ byte [] encodedKey = encodeHeaderKey (entry .getKey (), shouldEscape );
134
145
for (String value : values ) {
135
146
output .write (encodedKey );
136
147
output .write (COLON );
137
- output .write (encodeHeaderString (value , shouldEscape ));
148
+ output .write (encodeHeaderValue (value , shouldEscape ));
138
149
output .write (LF );
139
150
}
140
151
}
@@ -147,36 +158,62 @@ private void writeHeaders(StompCommand command, Map<String, Object> headers, byt
147
158
}
148
159
}
149
160
150
- private byte [] encodeHeaderString (String input , boolean escape ) {
161
+ private byte [] encodeHeaderKey (String input , boolean escape ) {
162
+ String inputToUse = (escape ? escape (input ) : input );
163
+ if (headerKeyCache .containsKey (inputToUse )) {
164
+ return headerKeyCache .get (inputToUse );
165
+ }
166
+ byte [] bytes = encodeHeaderString (inputToUse );
167
+ headerKeyCache .put (inputToUse , bytes );
168
+ return bytes ;
169
+ }
170
+
171
+ private byte [] encodeHeaderValue (String input , boolean escape ) {
151
172
String inputToUse = (escape ? escape (input ) : input );
152
- return inputToUse .getBytes (StandardCharsets .UTF_8 );
173
+ return encodeHeaderString (inputToUse );
174
+ }
175
+
176
+ private byte [] encodeHeaderString (String input ) {
177
+ return input .getBytes (StandardCharsets .UTF_8 );
153
178
}
154
179
155
180
/**
156
181
* See STOMP Spec 1.2:
157
182
* <a href="http://stomp.github.io/stomp-specification-1.2.html#Value_Encoding">"Value Encoding"</a>.
158
183
*/
159
184
private String escape (String inString ) {
160
- StringBuilder sb = new StringBuilder ( inString . length ()) ;
185
+ StringBuilder sb = null ;
161
186
for (int i = 0 ; i < inString .length (); i ++) {
162
187
char c = inString .charAt (i );
163
188
if (c == '\\' ) {
189
+ sb = getStringBuilder (sb , inString , i );
164
190
sb .append ("\\ \\ " );
165
191
}
166
192
else if (c == ':' ) {
193
+ sb = getStringBuilder (sb , inString , i );
167
194
sb .append ("\\ c" );
168
195
}
169
196
else if (c == '\n' ) {
170
- sb .append ("\\ n" );
197
+ sb = getStringBuilder (sb , inString , i );
198
+ sb .append ("\\ n" );
171
199
}
172
200
else if (c == '\r' ) {
201
+ sb = getStringBuilder (sb , inString , i );
173
202
sb .append ("\\ r" );
174
203
}
175
- else {
204
+ else if ( sb != null ) {
176
205
sb .append (c );
177
206
}
178
207
}
179
- return sb .toString ();
208
+ return (sb != null ? sb .toString () : inString );
209
+ }
210
+
211
+ private StringBuilder getStringBuilder (StringBuilder sb , String inString , int i ) {
212
+ if (sb == null ) {
213
+ sb = new StringBuilder (inString .length ());
214
+ sb .append (inString .substring (0 , i ));
215
+ }
216
+ return sb ;
180
217
}
181
218
182
219
private void writeBody (byte [] payload , DataOutputStream output ) throws IOException {
0 commit comments