46
46
* message string is then passed to MINA IO handlers for further processing.
47
47
*/
48
48
public class FIXMessageDecoder implements MessageDecoder {
49
+
49
50
private static final char SOH = '\001' ;
50
51
private static final String FIELD_DELIMITER = String .valueOf (SOH );
51
52
52
53
private final Logger log = LoggerFactory .getLogger (getClass ());
53
54
54
- private final byte [] HEADER_PATTERN ;
55
- private final byte [] CHECKSUM_PATTERN ;
56
- private final byte [] LOGON_PATTERN ;
55
+ private final PatternMatcher HEADER_PATTERN ;
56
+ private final PatternMatcher CHECKSUM_PATTERN ;
57
+ private final PatternMatcher LOGON_PATTERN ;
57
58
58
59
// Parsing states
59
60
private static final int SEEKING_HEADER = 1 ;
@@ -86,14 +87,14 @@ public FIXMessageDecoder(String charset) throws UnsupportedEncodingException {
86
87
87
88
public FIXMessageDecoder (String charset , String delimiter ) throws UnsupportedEncodingException {
88
89
charsetEncoding = CharsetSupport .validate (charset );
89
- HEADER_PATTERN = getBytes ("8=FIXt.?.?" + delimiter + "9=" );
90
- CHECKSUM_PATTERN = getBytes ("10=???" + delimiter );
91
- LOGON_PATTERN = getBytes (delimiter + "35=A" + delimiter );
90
+ HEADER_PATTERN = new PatternMatcher ("8=FIXt.?.?" + delimiter + "9=" );
91
+ CHECKSUM_PATTERN = new PatternMatcher ("10=???" + delimiter );
92
+ LOGON_PATTERN = new PatternMatcher (delimiter + "35=A" + delimiter );
92
93
resetState ();
93
94
}
94
95
95
96
public MessageDecoderResult decodable (IoSession session , IoBuffer in ) {
96
- boolean hasHeader = indexOf (in , in .position (), HEADER_PATTERN ) != -1L ;
97
+ boolean hasHeader = HEADER_PATTERN . find (in , in .position ()) != -1L ;
97
98
return hasHeader ? MessageDecoderResult .OK :
98
99
(in .remaining () > MAX_UNDECODED_DATA_LENGTH ? MessageDecoderResult .NOT_OK : MessageDecoderResult .NEED_DATA );
99
100
}
@@ -129,7 +130,7 @@ private boolean parseMessage(IoBuffer in, ProtocolDecoderOutput out)
129
130
while (in .hasRemaining () && !messageFound ) {
130
131
if (state == SEEKING_HEADER ) {
131
132
132
- long headerPos = indexOf (in , position , HEADER_PATTERN );
133
+ long headerPos = HEADER_PATTERN . find (in , position );
133
134
if (headerPos == -1L ) {
134
135
break ;
135
136
}
@@ -183,7 +184,7 @@ private boolean parseMessage(IoBuffer in, ProtocolDecoderOutput out)
183
184
}
184
185
185
186
if (state == PARSING_CHECKSUM ) {
186
- if (matches (in , position , CHECKSUM_PATTERN ) > 0 ) {
187
+ if (CHECKSUM_PATTERN . match (in , position ) > 0 ) {
187
188
// we are trying to parse the checksum but should
188
189
// check if the CHECKSUM_PATTERN is preceded by SOH
189
190
// or if the pattern just occurs inside of another field
@@ -195,9 +196,9 @@ private boolean parseMessage(IoBuffer in, ProtocolDecoderOutput out)
195
196
if (log .isDebugEnabled ()) {
196
197
log .debug ("found checksum: " + getBufferDebugInfo (in ));
197
198
}
198
- position += CHECKSUM_PATTERN .length ;
199
+ position += CHECKSUM_PATTERN .getMinLength () ;
199
200
} else {
200
- if (position + CHECKSUM_PATTERN .length <= in .limit ()) {
201
+ if (position + CHECKSUM_PATTERN .getMinLength () <= in .limit ()) {
201
202
// FEATURE allow configurable recovery position
202
203
// int recoveryPosition = in.position() + 1;
203
204
// Following recovery position is compatible with QuickFIX C++
@@ -250,16 +251,6 @@ private boolean hasRemaining(IoBuffer in) {
250
251
return position < in .limit ();
251
252
}
252
253
253
- private static int minPatternLength (byte [] pattern ) {
254
- int len = 0 ;
255
- for (byte b : pattern ) {
256
- if (b < 'a' || b > 'z' ) { // if not optional character (lowercase)
257
- len ++;
258
- }
259
- }
260
- return len ;
261
- }
262
-
263
254
private String getMessageString (IoBuffer buffer ) throws UnsupportedEncodingException {
264
255
byte [] data = new byte [position - buffer .position ()];
265
256
buffer .get (data );
@@ -288,68 +279,7 @@ private void handleError(IoBuffer buffer, int recoveryPosition, String text,
288
279
}
289
280
290
281
private boolean isLogon (IoBuffer buffer ) {
291
- return indexOf (buffer , buffer .position (), LOGON_PATTERN ) != -1L ;
292
- }
293
-
294
- /**
295
- * Searches for the given pattern within a buffer,
296
- * starting at the given buffer position.
297
- *
298
- * @param buffer the buffer to search within
299
- * @param position the buffer position to start searching at
300
- * @param pattern the pattern to search for
301
- * @return a long value whose lower 32 bits contain the index of the
302
- * found pattern, and upper 32 bits contain the found pattern length;
303
- * if the pattern is not found at all, returns -1L
304
- */
305
- private static long indexOf (IoBuffer buffer , int position , byte [] pattern ) {
306
- int length ;
307
- byte first = pattern [0 ];
308
- for (int limit = buffer .limit () - minPatternLength (pattern ) + 1 ; position < limit ; position ++) {
309
- if (buffer .get (position ) == first && (length = matches (buffer , position , pattern )) > 0 ) {
310
- return (long )length << 32 | position ;
311
- }
312
- }
313
- return -1L ;
314
- }
315
-
316
- /**
317
- * Checks if the buffer at the given offset matches the given pattern.
318
- * The character '?' is a one byte wildcard, and lowercase letters are optional.
319
- *
320
- * @param buffer the buffer to check
321
- * @param bufferOffset the buffer offset at which to check
322
- * @param pattern the pattern to try matching
323
- * @return the length of the matched pattern, or -1 if there is no match
324
- */
325
- private static int matches (IoBuffer buffer , int bufferOffset , byte [] pattern ) {
326
- if (bufferOffset + minPatternLength (pattern ) > buffer .limit ()) {
327
- return -1 ;
328
- }
329
- final int initOffset = bufferOffset ;
330
- int patternOffset = 0 ;
331
- for (int bufferLimit = buffer .limit (); patternOffset < pattern .length
332
- && bufferOffset < bufferLimit ; patternOffset ++, bufferOffset ++) {
333
- byte b = pattern [patternOffset ];
334
- // check exact character match or wildcard match
335
- if (buffer .get (bufferOffset ) == b || b == '?' )
336
- continue ;
337
- // check optional character match
338
- if (b >= 'a' && b <= 'z' ) { // lowercase is optional
339
- // at this point we know it's not an exact match, so we only need to check the
340
- // uppercase character. If there's a match we go on as usual, and if not we
341
- // ignore the optional character by rewinding the buffer offset
342
- if (b - 'a' + 'A' != buffer .get (bufferOffset )) // no uppercase match
343
- bufferOffset --;
344
- continue ;
345
- }
346
- return -1 ; // no match
347
- }
348
- if (patternOffset != pattern .length ) {
349
- // when minPatternLength(pattern) != pattern.length we might run out of buffer before we run out of pattern
350
- return -1 ;
351
- }
352
- return bufferOffset - initOffset ;
282
+ return LOGON_PATTERN .find (buffer , buffer .position ()) != -1L ;
353
283
}
354
284
355
285
public void finishDecode (IoSession arg0 , ProtocolDecoderOutput arg1 ) throws Exception {
@@ -419,11 +349,4 @@ public void flush(IoFilter.NextFilter nextFilter, IoSession ioSession) {
419
349
fileIn .close ();
420
350
}
421
351
422
- private static byte [] getBytes (String s ) {
423
- try {
424
- return s .getBytes (CharsetSupport .getDefaultCharset ());
425
- } catch (UnsupportedEncodingException e ) {
426
- throw new RuntimeException (e );
427
- }
428
- }
429
352
}
0 commit comments