4646 * message string is then passed to MINA IO handlers for further processing.
4747 */
4848public class FIXMessageDecoder implements MessageDecoder {
49+
4950 private static final char SOH = '\001' ;
5051 private static final String FIELD_DELIMITER = String .valueOf (SOH );
5152
5253 private final Logger log = LoggerFactory .getLogger (getClass ());
5354
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 ;
5758
5859 // Parsing states
5960 private static final int SEEKING_HEADER = 1 ;
@@ -86,14 +87,14 @@ public FIXMessageDecoder(String charset) throws UnsupportedEncodingException {
8687
8788 public FIXMessageDecoder (String charset , String delimiter ) throws UnsupportedEncodingException {
8889 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 );
9293 resetState ();
9394 }
9495
9596 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 ;
9798 return hasHeader ? MessageDecoderResult .OK :
9899 (in .remaining () > MAX_UNDECODED_DATA_LENGTH ? MessageDecoderResult .NOT_OK : MessageDecoderResult .NEED_DATA );
99100 }
@@ -129,7 +130,7 @@ private boolean parseMessage(IoBuffer in, ProtocolDecoderOutput out)
129130 while (in .hasRemaining () && !messageFound ) {
130131 if (state == SEEKING_HEADER ) {
131132
132- long headerPos = indexOf (in , position , HEADER_PATTERN );
133+ long headerPos = HEADER_PATTERN . find (in , position );
133134 if (headerPos == -1L ) {
134135 break ;
135136 }
@@ -183,7 +184,7 @@ private boolean parseMessage(IoBuffer in, ProtocolDecoderOutput out)
183184 }
184185
185186 if (state == PARSING_CHECKSUM ) {
186- if (matches (in , position , CHECKSUM_PATTERN ) > 0 ) {
187+ if (CHECKSUM_PATTERN . match (in , position ) > 0 ) {
187188 // we are trying to parse the checksum but should
188189 // check if the CHECKSUM_PATTERN is preceded by SOH
189190 // or if the pattern just occurs inside of another field
@@ -195,9 +196,9 @@ private boolean parseMessage(IoBuffer in, ProtocolDecoderOutput out)
195196 if (log .isDebugEnabled ()) {
196197 log .debug ("found checksum: " + getBufferDebugInfo (in ));
197198 }
198- position += CHECKSUM_PATTERN .length ;
199+ position += CHECKSUM_PATTERN .getMinLength () ;
199200 } else {
200- if (position + CHECKSUM_PATTERN .length <= in .limit ()) {
201+ if (position + CHECKSUM_PATTERN .getMinLength () <= in .limit ()) {
201202 // FEATURE allow configurable recovery position
202203 // int recoveryPosition = in.position() + 1;
203204 // Following recovery position is compatible with QuickFIX C++
@@ -250,16 +251,6 @@ private boolean hasRemaining(IoBuffer in) {
250251 return position < in .limit ();
251252 }
252253
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-
263254 private String getMessageString (IoBuffer buffer ) throws UnsupportedEncodingException {
264255 byte [] data = new byte [position - buffer .position ()];
265256 buffer .get (data );
@@ -288,68 +279,7 @@ private void handleError(IoBuffer buffer, int recoveryPosition, String text,
288279 }
289280
290281 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 ;
353283 }
354284
355285 public void finishDecode (IoSession arg0 , ProtocolDecoderOutput arg1 ) throws Exception {
@@ -419,11 +349,4 @@ public void flush(IoFilter.NextFilter nextFilter, IoSession ioSession) {
419349 fileIn .close ();
420350 }
421351
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- }
429352}
0 commit comments