2121import java .io .IOException ;
2222import java .nio .charset .StandardCharsets ;
2323import java .util .Collections ;
24+ import java .util .LinkedHashMap ;
2425import java .util .List ;
2526import java .util .Map ;
2627import java .util .Map .Entry ;
@@ -50,6 +51,16 @@ public class StompEncoder {
5051
5152 private static final Log logger = LogFactory .getLog (StompEncoder .class );
5253
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+ };
5364
5465 /**
5566 * Encodes the given STOMP {@code message} into a {@code byte[]}
@@ -130,11 +141,11 @@ private void writeHeaders(StompCommand command, Map<String, Object> headers, byt
130141 values = Collections .singletonList (StompHeaderAccessor .getPasscode (headers ));
131142 }
132143
133- byte [] encodedKey = encodeHeaderString (entry .getKey (), shouldEscape );
144+ byte [] encodedKey = encodeHeaderKey (entry .getKey (), shouldEscape );
134145 for (String value : values ) {
135146 output .write (encodedKey );
136147 output .write (COLON );
137- output .write (encodeHeaderString (value , shouldEscape ));
148+ output .write (encodeHeaderValue (value , shouldEscape ));
138149 output .write (LF );
139150 }
140151 }
@@ -147,36 +158,62 @@ private void writeHeaders(StompCommand command, Map<String, Object> headers, byt
147158 }
148159 }
149160
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 ) {
151172 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 );
153178 }
154179
155180 /**
156181 * See STOMP Spec 1.2:
157182 * <a href="http://stomp.github.io/stomp-specification-1.2.html#Value_Encoding">"Value Encoding"</a>.
158183 */
159184 private String escape (String inString ) {
160- StringBuilder sb = new StringBuilder ( inString . length ()) ;
185+ StringBuilder sb = null ;
161186 for (int i = 0 ; i < inString .length (); i ++) {
162187 char c = inString .charAt (i );
163188 if (c == '\\' ) {
189+ sb = getStringBuilder (sb , inString , i );
164190 sb .append ("\\ \\ " );
165191 }
166192 else if (c == ':' ) {
193+ sb = getStringBuilder (sb , inString , i );
167194 sb .append ("\\ c" );
168195 }
169196 else if (c == '\n' ) {
170- sb .append ("\\ n" );
197+ sb = getStringBuilder (sb , inString , i );
198+ sb .append ("\\ n" );
171199 }
172200 else if (c == '\r' ) {
201+ sb = getStringBuilder (sb , inString , i );
173202 sb .append ("\\ r" );
174203 }
175- else {
204+ else if ( sb != null ) {
176205 sb .append (c );
177206 }
178207 }
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 ;
180217 }
181218
182219 private void writeBody (byte [] payload , DataOutputStream output ) throws IOException {
0 commit comments