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 ;
28+ import java .util .concurrent .ConcurrentHashMap ;
2729
2830import org .apache .commons .logging .Log ;
2931import org .apache .commons .logging .LogFactory ;
@@ -50,6 +52,27 @@ public class StompEncoder {
5052
5153 private static final Log logger = LogFactory .getLog (StompEncoder .class );
5254
55+ private static final int HEADER_KEY_CACHE_LIMIT = 32 ;
56+
57+
58+ private final Map <String , byte []> headerKeyAccessCache =
59+ new ConcurrentHashMap <>(HEADER_KEY_CACHE_LIMIT );
60+
61+ @ SuppressWarnings ("serial" )
62+ private final Map <String , byte []> headerKeyUpdateCache =
63+ new LinkedHashMap <String , byte []>(HEADER_KEY_CACHE_LIMIT , 0.75f , true ) {
64+ @ Override
65+ protected boolean removeEldestEntry (Map .Entry <String , byte []> eldest ) {
66+ if (size () > HEADER_KEY_CACHE_LIMIT ) {
67+ headerKeyAccessCache .remove (eldest .getKey ());
68+ return true ;
69+ }
70+ else {
71+ return false ;
72+ }
73+ }
74+ };
75+
5376
5477 /**
5578 * Encodes the given STOMP {@code message} into a {@code byte[]}
@@ -130,11 +153,11 @@ private void writeHeaders(StompCommand command, Map<String, Object> headers, byt
130153 values = Collections .singletonList (StompHeaderAccessor .getPasscode (headers ));
131154 }
132155
133- byte [] encodedKey = encodeHeaderString (entry .getKey (), shouldEscape );
156+ byte [] encodedKey = encodeHeaderKey (entry .getKey (), shouldEscape );
134157 for (String value : values ) {
135158 output .write (encodedKey );
136159 output .write (COLON );
137- output .write (encodeHeaderString (value , shouldEscape ));
160+ output .write (encodeHeaderValue (value , shouldEscape ));
138161 output .write (LF );
139162 }
140163 }
@@ -147,7 +170,23 @@ private void writeHeaders(StompCommand command, Map<String, Object> headers, byt
147170 }
148171 }
149172
150- private byte [] encodeHeaderString (String input , boolean escape ) {
173+ private byte [] encodeHeaderKey (String input , boolean escape ) {
174+ String inputToUse = (escape ? escape (input ) : input );
175+ if (this .headerKeyAccessCache .containsKey (inputToUse )) {
176+ return this .headerKeyAccessCache .get (inputToUse );
177+ }
178+ synchronized (this .headerKeyUpdateCache ) {
179+ byte [] bytes = this .headerKeyUpdateCache .get (inputToUse );
180+ if (bytes == null ) {
181+ bytes = inputToUse .getBytes (StandardCharsets .UTF_8 );
182+ this .headerKeyAccessCache .put (inputToUse , bytes );
183+ this .headerKeyUpdateCache .put (inputToUse , bytes );
184+ }
185+ return bytes ;
186+ }
187+ }
188+
189+ private byte [] encodeHeaderValue (String input , boolean escape ) {
151190 String inputToUse = (escape ? escape (input ) : input );
152191 return inputToUse .getBytes (StandardCharsets .UTF_8 );
153192 }
@@ -157,26 +196,38 @@ private byte[] encodeHeaderString(String input, boolean escape) {
157196 * <a href="http://stomp.github.io/stomp-specification-1.2.html#Value_Encoding">"Value Encoding"</a>.
158197 */
159198 private String escape (String inString ) {
160- StringBuilder sb = new StringBuilder ( inString . length ()) ;
199+ StringBuilder sb = null ;
161200 for (int i = 0 ; i < inString .length (); i ++) {
162201 char c = inString .charAt (i );
163202 if (c == '\\' ) {
203+ sb = getStringBuilder (sb , inString , i );
164204 sb .append ("\\ \\ " );
165205 }
166206 else if (c == ':' ) {
207+ sb = getStringBuilder (sb , inString , i );
167208 sb .append ("\\ c" );
168209 }
169210 else if (c == '\n' ) {
170- sb .append ("\\ n" );
211+ sb = getStringBuilder (sb , inString , i );
212+ sb .append ("\\ n" );
171213 }
172214 else if (c == '\r' ) {
215+ sb = getStringBuilder (sb , inString , i );
173216 sb .append ("\\ r" );
174217 }
175- else {
218+ else if ( sb != null ) {
176219 sb .append (c );
177220 }
178221 }
179- return sb .toString ();
222+ return (sb != null ? sb .toString () : inString );
223+ }
224+
225+ private StringBuilder getStringBuilder (StringBuilder sb , String inString , int i ) {
226+ if (sb == null ) {
227+ sb = new StringBuilder (inString .length ());
228+ sb .append (inString .substring (0 , i ));
229+ }
230+ return sb ;
180231 }
181232
182233 private void writeBody (byte [] payload , DataOutputStream output ) throws IOException {
0 commit comments