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.codec.delimited.ints;
    21
    22  import java.nio.BufferUnderflowException;
    23  import java.nio.ByteBuffer;
    24  import java.nio.ByteOrder;
    25
    26  import org.apache.mina.codec.IoBuffer;
    27  import org.apache.mina.codec.delimited.ByteBufferEncoder;
    28  import org.apache.mina.codec.delimited.IoBufferDecoder;
    29
    30  /**
    31   *
    32   * Class providing raw/canonical representation of integers.
    33   *
    34   *
    35   * <style type="text/css"> pre-fw { color: rgb(0, 0, 0); display: block;
    36   * font-family:courier, "courier new", monospace; font-size: 13px; white-space:
    37   * pre; } </style>
    38   *
    39   * <h2>RawInt32 encoder and decoder</h2>
    40   * <p>
    41   * This pair provides a mechanism called canonical form serialization.
    42   *
    43   * In this representations all 32-bits integer are encoded over 4 bytes.
    44   *
    45   *
    46   * This library provides two variants <i>big-endian</i> and <i>small-endian</i>.
    47   *
    48   *
    49   * In both cases, the inner bits of each byte are ordered from the most to the
    50   * least significant bit.
    51   *
    52   * The difference between the two variants is the ordering of the four bytes.
    53   *
    54   * <ul>
    55   * <li>Big-endian: <i>The bytes are ordered from the most to the least
    56   * significant one</i></li>
    57   * <li>Little-endian: <i>The bytes are ordered from the least to the most
    58   * significant one</i></li>
    59   * </ul>
    60   *
    61   * <p>
    62   * This representation is often used since it is used internally in CPUs,
    63   * therefore programmers using a low level languages (assembly, C, ...)
    64   * appreciate using it (for ease of use or performance reasons). When integers
    65   * are directly copied from memory, it is required to ensure this serializer
    66   * uses the appropriate endianness on both ends.
    67   * <ul>
    68   * <li>Big-endian: 68k, MIPS, Alpha, SPARC</li>
    69   * <li>Little-endian: x86, x86-64, ARM</li>
    70   * <li><i>Bi-</i>endian (depends of the operating system): PowerPC, Itanium</li>
    71   * </ul>
    72   * </p>
    73   *
    74   * <p>
    75   * More details availabile on the Wikipedia
    76   * "<a href="http://en.wikipedia.org/wiki/Endianness">Endianness page</a>".
    77   * </p>
    78   *
    79   * <h2>On-wire representation</h2>
    80   * <p>
    81   * Encoding of the value 67305985
    82   * </p>
    83   * <i>Big-Endian variant:</i>
    84   *
    85   * <pre-fw>
    86   * 0000 0100  0000 0011  0000 0010  0000 0001
    87   * ‾‾‾‾↓‾‾‾‾  ‾‾‾‾↓‾‾‾‾  ‾‾‾‾↓‾‾‾‾  ‾‾‾‾↓‾‾‾‾
    88   *     4          3          2          1      // 4·2<sup>24</sup> + 3·2<sup>16</sup> + 2·2<sup>8</sup> + 1·2<sup>0</sup>  = 67305985
    89   *
    90   * </pre-fw>
    91   *
    92   * <i>Little-Endian variant:</i>
    93   *
    94   * <pre-fw>
    95   * 0000 0001  0000 0010  0000 0011  0000 0100
    96   * ‾‾‾‾↓‾‾‾‾  ‾‾‾‾↓‾‾‾‾  ‾‾‾‾↓‾‾‾‾  ‾‾‾‾↓‾‾‾‾
    97   *     1          2          3          4      // 1·2<sup>0</sup> + 2·2<sup>8</sup> + 3·2<sup>16</sup> + 4·2<sup>24</sup>  = 67305985
    98   * </pre-fw>
    99   *
    100  * </p>
    101  *
    102  * <p>
    103  * n.b. This class doesn't have any dependency against Apache Thrift or any
    104  * other library in order to provide this convenient integer serialization
    105  * module to any software using FramedMINA.
    106  * </p>
    107  *
    108  * @author <a href="http://mina.apache.org">Apache MINA Project</a>
    109  */
    110 /*
    111  * About the suppression of warnings:
    112  * This class contains a lot of bit-shifting, logical and/or operations order to handle
    113  * VarInt conversions. The code contains a lot of hard-coded integer that tools like
    114  * Sonar classify as "magic numbers". Using final static variables for all of them
    115  * would have resulted in a code less readable.
    116  * The "all" scope is too generic, but Sonar doesn't not handle properly others scopes
    117  * like "MagicNumber" (Sonar 3.6 - 03July2013)
    118  */
    119 @SuppressWarnings("all")
    120 public final class RawInt32 implements IntTranscoder {
    121     private final ByteOrder bo;
    122
    123     public RawInt32(ByteOrder bo) {
    124         super();
    125         this.bo = bo == null ? ByteOrder.BIG_ENDIAN : bo;
    126     }
    127
    128     @Override
    129     public IoBufferDecoder<Integer> getDecoder() {
    130         return new Decoder();
    131     }
    132
    133     @Override
    134     public ByteBufferEncoder<Integer> getEncoder() {
    135         return new Encoder();
    136     }
    137
    138     private static final int BYTE_MASK = 0xff;
    139
    140     /**
    141      * Documentation available in the {@link RawInt32} enclosing class.
    142      *
    143      * @author <a href="http://mina.apache.org">Apache MINA Project</a>
    144      *
    145      */
    146     private class Decoder extends IoBufferDecoder<Integer> {
    147
    148         @Override
    149         public Integer decode(IoBuffer input) {
    150             if (input.remaining() < 4) {
    151                 return null;
    152             }
    153
    154             int out = 0;
    155             for (int i = 0; i < 32; i += 8) {
    156                 out |= (input.get() & 0xff) << (bo == ByteOrder.BIG_ENDIAN ? 24 - i : i);
    157             }
    158             return out;
    159         }
    160     }
    161
    162     /**
    163      * Documentation available in the {@link RawInt32} enclosing class.
    164      *
    165      * @author <a href="http://mina.apache.org">Apache MINA Project</a>
    166      *
    167      */
    168     private class Encoder extends ByteBufferEncoder<Integer> {
    169
    170         @Override
    171         public void writeTo(Integer message, ByteBuffer buffer) {
    172
    173             if (buffer.remaining() < 4) {
    174                 throw new BufferUnderflowException();
    175             }
    176             for (int i = 0; i < 32; i += 8) {
    177                 buffer.put((byte) (message >> (bo == ByteOrder.BIG_ENDIAN ? 24 - i : i)));
    178             }
    179         }
    180
    181         @Override
    182         public int getEncodedSize(Integer message) {
    183             return 4;
    184         }
    185
    186     }
    187 }