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 }