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;
    21
    22  import java.nio.ByteBuffer;
    23
    24  import org.apache.mina.api.AbstractIoFilter;
    25  import org.apache.mina.api.IoFilter;
    26  import org.apache.mina.api.IoSession;
    27  import org.apache.mina.codec.ProtocolDecoder;
    28  import org.apache.mina.codec.ProtocolDecoderException;
    29  import org.apache.mina.codec.ProtocolEncoder;
    30  import org.apache.mina.filterchain.ReadFilterChainController;
    31  import org.apache.mina.filterchain.WriteFilterChainController;
    32  import org.apache.mina.session.AttributeKey;
    33  import org.apache.mina.session.WriteRequest;
    34  import org.apache.mina.util.Assert;
    35  import org.slf4j.Logger;
    36  import org.slf4j.LoggerFactory;
    37
    38  /**
    39   * An {@link IoFilter} which translates binary or protocol specific data into message objects and vice versa using
    40   * {@link ProtocolCodecFactory}, {@link ProtocolEncoder}, or {@link ProtocolDecoder}.
    41   *
    42   * @param MESSAGE the kind of high level business message this filter will encode and decode.
    43   * @param ENCODED the kind of low level message (most of time {@link ByteBuffer}) this filter will produce of consume.
    44   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
    45   */
    46  public class ProtocolCodecFilter<MESSAGE, ENCODED, ENCODING_STATE, DECODING_STATE> extends AbstractIoFilter {
    47      /** A logger for this class */
    48      private static final Logger LOGGER = LoggerFactory.getLogger(ProtocolCodecFilter.class);
    49
    50      /** the immutable encoder */
    51      private final ProtocolEncoder<MESSAGE, ENCODED, ENCODING_STATE> encoder;
    52
    53      /** the immutable decoder */
    54      private final ProtocolDecoder<ENCODED, MESSAGE, DECODING_STATE> decoder;
    55
    56      /** key for session attribute holding the encoder */
    57      private static final AttributeKey<Object> ENCODER = new AttributeKey<Object>(Object.class, "internal_encoder");
    58
    59      /** key for session attribute holding the decoder */
    60      private static final AttributeKey<Object> DECODER = new AttributeKey<Object>(Object.class, "internal_decoder");
    61
    62      /**
    63       * Creates a new instance of ProtocolCodecFilter, with the specified encoder and decoder.
    64       *
    65       */
    66      public ProtocolCodecFilter(ProtocolEncoder<MESSAGE, ENCODED, ENCODING_STATE> encoder,
    67              ProtocolDecoder<ENCODED, MESSAGE, DECODING_STATE> decoder) {
    68          Assert.assertNotNull(encoder, "encoder");
    69          Assert.assertNotNull(decoder, "decoder");
    70          this.encoder = encoder;
    71          this.decoder = decoder;
    72      }
    73
    74      /**
    75       * Process the incoming message, calling the session decoder. As the incoming buffer might contains more than one
    76       * messages, we have to loop until the decoder throws an exception. <code>
    77       *  while ( buffer not empty )
    78       *    try
    79       *      decode ( buffer )
    80       *    catch
    81       *      break;
    82       * </code>
    83       */
    84      @SuppressWarnings("unchecked")
    85      @Override
    86      public void messageReceived(IoSession session, Object in, ReadFilterChainController controller) {
    87          LOGGER.debug("Processing a MESSAGE_RECEIVED for session {}", session);
    88
    89          DECODING_STATE state = getDecodingState(session);
    90
    91          // Loop until the decoder cannot decode more
    92          MESSAGE msg;
    93          try {
    94              while (((msg = decoder.decode((ENCODED) in, state)) != null)) {
    95                  controller.callReadNextFilter(msg);
    96              }
    97          } catch (ProtocolDecoderException e) {
    98              LOGGER.debug("decoding exception : ", e);
    99              throw e;
    100         }
    101     }
    102
    103     /**
    104      * {@inheritDoc}
    105      */
    106     @SuppressWarnings("unchecked")
    107     @Override
    108     public void messageWriting(IoSession session, WriteRequest message, WriteFilterChainController controller) {
    109         LOGGER.debug("Processing a MESSAGE_WRITTING for session {}", session);
    110
    111         ENCODED encoded = encoder.encode((MESSAGE) message.getMessage(), getEncodingState(session));
    112         message.setMessage(encoded);
    113
    114         controller.callWriteNextFilter(message);
    115     }
    116
    117     /**
    118      * {@inheritDoc}
    119      */
    120     @Override
    121     public void sessionOpened(IoSession session) {
    122         // Initialize the encoder and decoder state
    123
    124         ENCODING_STATE encodingState = encoder.createEncoderState();
    125         session.setAttribute(ENCODER, encodingState);
    126
    127         DECODING_STATE decodingState = decoder.createDecoderState();
    128         session.setAttribute(DECODER, decodingState);
    129     }
    130
    131     /**
    132      * {@inheritDoc}
    133      */
    134     @Override
    135     public void sessionClosed(IoSession session) {
    136         decoder.finishDecode(getDecodingState(session));
    137
    138     }
    139
    140     // ----------- Helper methods ---------------------------------------------
    141
    142     @SuppressWarnings("unchecked")
    143     private DECODING_STATE getDecodingState(IoSession session) {
    144         return (DECODING_STATE) session.getAttribute(DECODER);
    145     }
    146
    147     @SuppressWarnings("unchecked")
    148     private ENCODING_STATE getEncodingState(IoSession session) {
    149         return (ENCODING_STATE) session.getAttribute(ENCODER);
    150     }
    151
    152 }