View Javadoc

    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one
    3    *  or more contributor license agreements.  See the NOTICE file
    4    *  distributed with this work for additional information
    5    *  regarding copyright ownership.  The ASF licenses this file
    6    *  to you under the Apache License, Version 2.0 (the
    7    *  "License"); you may not use this file except in compliance
    8    *  with the License.  You may obtain a copy of the License at
    9    *
    10   *    http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   *  Unless required by applicable law or agreed to in writing,
    13   *  software distributed under the License is distributed on an
    14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    15   *  KIND, either express or implied.  See the License for the
    16   *  specific language governing permissions and limitations
    17   *  under the License.
    18   *
    19   */
    20  package org.apache.mina.filter.codec.statemachine;
    21
    22  import org.apache.mina.core.buffer.IoBuffer;
    23  import org.apache.mina.filter.codec.ProtocolDecoderOutput;
    24
    25  /**
    26   * {@link DecodingState} which consumes all bytes until a fixed (ASCII)
    27   * character is reached. The terminator is skipped.
    28   *
    29   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
    30   */
    31  public abstract class ConsumeToDynamicTerminatorDecodingState implements DecodingState {
    32
    33      private IoBuffer buffer;
    34
    35      /**
    36       * {@inheritDoc}
    37       */
    38      public DecodingState decode(IoBuffer in, ProtocolDecoderOutput out) throws Exception {
    39          int beginPos = in.position();
    40          int terminatorPos = -1;
    41          int limit = in.limit();
    42
    43          for (int i = beginPos; i < limit; i++) {
    44              byte b = in.get(i);
    45              if (isTerminator(b)) {
    46                  terminatorPos = i;
    47                  break;
    48              }
    49          }
    50
    51          if (terminatorPos >= 0) {
    52              IoBuffer product;
    53
    54              if (beginPos < terminatorPos) {
    55                  in.limit(terminatorPos);
    56
    57                  if (buffer == null) {
    58                      product = in.slice();
    59                  } else {
    60                      buffer.put(in);
    61                      product = buffer.flip();
    62                      buffer = null;
    63                  }
    64
    65                  in.limit(limit);
    66              } else {
    67                  // When input contained only terminator rather than actual data...
    68                  if (buffer == null) {
    69                      product = IoBuffer.allocate(0);
    70                  } else {
    71                      product = buffer.flip();
    72                      buffer = null;
    73                  }
    74              }
    75              in.position(terminatorPos + 1);
    76              return finishDecode(product, out);
    77          }
    78
    79          if (buffer == null) {
    80              buffer = IoBuffer.allocate(in.remaining());
    81              buffer.setAutoExpand(true);
    82          }
    83          buffer.put(in);
    84          return this;
    85      }
    86
    87      /**
    88       * {@inheritDoc}
    89       */
    90      public DecodingState finishDecode(ProtocolDecoderOutput out) throws Exception {
    91          IoBuffer product;
    92          // When input contained only terminator rather than actual data...
    93          if (buffer == null) {
    94              product = IoBuffer.allocate(0);
    95          } else {
    96              product = buffer.flip();
    97              buffer = null;
    98          }
    99          return finishDecode(product, out);
    100     }
    101
    102     /**
    103      * Determines whether the specified <code>byte</code> is a terminator.
    104      *
    105      * @param b the <code>byte</code> to check.
    106      * @return <code>true</code> if <code>b</code> is a terminator,
    107      *         <code>false</code> otherwise.
    108      */
    109     protected abstract boolean isTerminator(byte b);
    110
    111     /**
    112      * Invoked when this state has reached the terminator byte.
    113      *
    114      * @param product the read bytes not including the terminator.
    115      * @param out the current {@link ProtocolDecoderOutput} used to write
    116      *        decoded messages.
    117      * @return the next state if a state transition was triggered (use
    118      *         <code>this</code> for loop transitions) or <code>null</code> if
    119      *         the state machine has reached its end.
    120      * @throws Exception if the read data violated protocol specification.
    121      */
    122     protected abstract DecodingState finishDecode(IoBuffer product, ProtocolDecoderOutput out) throws Exception;
    123 }