@ -21,9 +21,11 @@ import java.io.DataOutputStream;
@@ -21,9 +21,11 @@ import java.io.DataOutputStream;
import java.io.IOException ;
import java.nio.charset.StandardCharsets ;
import java.util.Collections ;
import java.util.LinkedHashMap ;
import java.util.List ;
import java.util.Map ;
import java.util.Map.Entry ;
import java.util.concurrent.ConcurrentHashMap ;
import org.apache.commons.logging.Log ;
import org.apache.commons.logging.LogFactory ;
@ -50,6 +52,27 @@ public class StompEncoder {
@@ -50,6 +52,27 @@ public class StompEncoder {
private static final Log logger = LogFactory . getLog ( StompEncoder . class ) ;
private static final int HEADER_KEY_CACHE_LIMIT = 32 ;
private final Map < String , byte [ ] > headerKeyAccessCache =
new ConcurrentHashMap < > ( HEADER_KEY_CACHE_LIMIT ) ;
@SuppressWarnings ( "serial" )
private final Map < String , byte [ ] > headerKeyUpdateCache =
new LinkedHashMap < String , byte [ ] > ( HEADER_KEY_CACHE_LIMIT , 0 . 75f , true ) {
@Override
protected boolean removeEldestEntry ( Map . Entry < String , byte [ ] > eldest ) {
if ( size ( ) > HEADER_KEY_CACHE_LIMIT ) {
headerKeyAccessCache . remove ( eldest . getKey ( ) ) ;
return true ;
}
else {
return false ;
}
}
} ;
/ * *
* Encodes the given STOMP { @code message } into a { @code byte [ ] }
@ -130,11 +153,11 @@ public class StompEncoder {
@@ -130,11 +153,11 @@ public class StompEncoder {
values = Collections . singletonList ( StompHeaderAccessor . getPasscode ( headers ) ) ;
}
byte [ ] encodedKey = encodeHeaderString ( entry . getKey ( ) , shouldEscape ) ;
byte [ ] encodedKey = encodeHeaderKey ( entry . getKey ( ) , shouldEscape ) ;
for ( String value : values ) {
output . write ( encodedKey ) ;
output . write ( COLON ) ;
output . write ( encodeHeaderString ( value , shouldEscape ) ) ;
output . write ( encodeHeaderValue ( value , shouldEscape ) ) ;
output . write ( LF ) ;
}
}
@ -147,7 +170,23 @@ public class StompEncoder {
@@ -147,7 +170,23 @@ public class StompEncoder {
}
}
private byte [ ] encodeHeaderString ( String input , boolean escape ) {
private byte [ ] encodeHeaderKey ( String input , boolean escape ) {
String inputToUse = ( escape ? escape ( input ) : input ) ;
if ( this . headerKeyAccessCache . containsKey ( inputToUse ) ) {
return this . headerKeyAccessCache . get ( inputToUse ) ;
}
synchronized ( this . headerKeyUpdateCache ) {
byte [ ] bytes = this . headerKeyUpdateCache . get ( inputToUse ) ;
if ( bytes = = null ) {
bytes = inputToUse . getBytes ( StandardCharsets . UTF_8 ) ;
this . headerKeyAccessCache . put ( inputToUse , bytes ) ;
this . headerKeyUpdateCache . put ( inputToUse , bytes ) ;
}
return bytes ;
}
}
private byte [ ] encodeHeaderValue ( String input , boolean escape ) {
String inputToUse = ( escape ? escape ( input ) : input ) ;
return inputToUse . getBytes ( StandardCharsets . UTF_8 ) ;
}
@ -157,26 +196,38 @@ public class StompEncoder {
@@ -157,26 +196,38 @@ public class StompEncoder {
* < a href = "http://stomp.github.io/stomp-specification-1.2.html#Value_Encoding" > "Value Encoding" < / a > .
* /
private String escape ( String inString ) {
StringBuilder sb = new Stri ngB ui lder ( inString . length ( ) ) ;
StringBuilder sb = null ;
for ( int i = 0 ; i < inString . length ( ) ; i + + ) {
char c = inString . charAt ( i ) ;
if ( c = = '\\' ) {
sb = getStringBuilder ( sb , inString , i ) ;
sb . append ( "\\\\" ) ;
}
else if ( c = = ':' ) {
sb = getStringBuilder ( sb , inString , i ) ;
sb . append ( "\\c" ) ;
}
else if ( c = = '\n' ) {
sb . append ( "\\n" ) ;
sb = getStringBuilder ( sb , inString , i ) ;
sb . append ( "\\n" ) ;
}
else if ( c = = '\r' ) {
sb = getStringBuilder ( sb , inString , i ) ;
sb . append ( "\\r" ) ;
}
else {
else if ( sb ! = null ) {
sb . append ( c ) ;
}
}
return sb . toString ( ) ;
return ( sb ! = null ? sb . toString ( ) : inString ) ;
}
private StringBuilder getStringBuilder ( StringBuilder sb , String inString , int i ) {
if ( sb = = null ) {
sb = new StringBuilder ( inString . length ( ) ) ;
sb . append ( inString . substring ( 0 , i ) ) ;
}
return sb ;
}
private void writeBody ( byte [ ] payload , DataOutputStream output ) throws IOException {