Updated Branches: refs/heads/trunk b9f507c1b -> 1c856929e
int serializations redesign and fixes Project: http://git-wip-us.apache.org/repos/asf/mina/repo Commit: http://git-wip-us.apache.org/repos/asf/mina/commit/ed496202 Tree: http://git-wip-us.apache.org/repos/asf/mina/tree/ed496202 Diff: http://git-wip-us.apache.org/repos/asf/mina/diff/ed496202 Branch: refs/heads/trunk Commit: ed49620224d1224956e1c23b84b29ddc52c9efd2 Parents: b9f507c Author: RaphaeÌl P. Barazzutti <[email protected]> Authored: Wed Jul 3 21:11:53 2013 +0200 Committer: RaphaeÌl P. Barazzutti <[email protected]> Committed: Thu Jul 4 00:39:46 2013 +0200 ---------------------------------------------------------------------- .../java/org/apache/mina/codec/IoBuffer.java | 58 +++++++++- .../mina/codec/delimited/ByteBufferDecoder.java | 104 ------------------ .../mina/codec/delimited/IoBufferDecoder.java | 105 +++++++++++++++++++ .../codec/delimited/SizePrefixedDecoder.java | 15 ++- .../codec/delimited/ints/IntTranscoder.java | 10 ++ .../mina/codec/delimited/ints/RawInt32.java | 105 ++++++++----------- .../mina/codec/delimited/ints/VarInt.java | 104 ++++++++++++------ .../serialization/JavaNativeMessageDecoder.java | 11 +- .../codec/delimited/ints/IntEncodingTest.java | 35 ++++--- .../ints/RawInt32BigEndianEncodingTest.java | 10 +- .../ints/RawInt32LittleEndianEncodingTest.java | 10 +- .../delimited/ints/VarIntEncodingTest.java | 8 +- .../serialization/GenericSerializerTest.java | 17 +-- .../delimited/serialization/JavaNativeTest.java | 4 +- 14 files changed, 341 insertions(+), 255 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mina/blob/ed496202/codec/src/main/java/org/apache/mina/codec/IoBuffer.java ---------------------------------------------------------------------- diff --git a/codec/src/main/java/org/apache/mina/codec/IoBuffer.java b/codec/src/main/java/org/apache/mina/codec/IoBuffer.java index 605ca24..1be49a5 100644 --- a/codec/src/main/java/org/apache/mina/codec/IoBuffer.java +++ b/codec/src/main/java/org/apache/mina/codec/IoBuffer.java @@ -20,6 +20,7 @@ package org.apache.mina.codec; import java.io.IOException; import java.io.InputStream; +import java.nio.BufferOverflowException; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -327,7 +328,7 @@ public final class IoBuffer { * @see ByteBuffer#get() */ public byte get() { - if (position.getPosition() >= limit.getPosition()) { + if (!hasRemaining()) { throw new BufferUnderflowException(); } @@ -551,6 +552,13 @@ public final class IoBuffer { } /** + * @see ByteBuffer#isReadOnly() + */ + public boolean isReadOnly() { + return readonly; + } + + /** * @see ByteBuffer#limit() */ public int limit() { @@ -645,6 +653,48 @@ public final class IoBuffer { } /** + * @see ByteBuffer#put(ByteBuffer) + */ + public IoBuffer put(ByteBuffer src) { + + if (remaining() < src.remaining()) { + throw new BufferOverflowException(); + } + if (isReadOnly()) { + throw new ReadOnlyBufferException(); + } + + while (src.hasRemaining()) { + put(src.get()); + } + + return this; + } + + + /** + * @see ByteBuffer#put(ByteBuffer) + */ + public IoBuffer put(IoBuffer src) { + if(src==this){ // NOSONAR, checking the instance + throw new IllegalArgumentException(); + } + + if (remaining() < src.remaining()) { + throw new BufferOverflowException(); + } + if (isReadOnly()) { + throw new ReadOnlyBufferException(); + } + + while (src.hasRemaining()) { + put(src.get()); + } + + return this; + } + + /** * @see ByteBuffer#put(byte[], int, int) */ public IoBuffer put(byte[] src, int offset, int length) { @@ -996,10 +1046,10 @@ public final class IoBuffer { public String toString() { StringBuffer sb = new StringBuffer(); sb.append(getClass().getName()); - sb.append("[node="); - sb.append(getNode()); - sb.append(", pos="); + sb.append("[pos="); sb.append(getPosition()); + sb.append(", node="); + sb.append(getNode()); sb.append("]"); return sb.toString(); } http://git-wip-us.apache.org/repos/asf/mina/blob/ed496202/codec/src/main/java/org/apache/mina/codec/delimited/ByteBufferDecoder.java ---------------------------------------------------------------------- diff --git a/codec/src/main/java/org/apache/mina/codec/delimited/ByteBufferDecoder.java b/codec/src/main/java/org/apache/mina/codec/delimited/ByteBufferDecoder.java deleted file mode 100644 index 73b6bbf..0000000 --- a/codec/src/main/java/org/apache/mina/codec/delimited/ByteBufferDecoder.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.mina.codec.delimited; - -import java.nio.ByteBuffer; - -import org.apache.mina.codec.ProtocolDecoder; -import org.apache.mina.codec.ProtocolDecoderException; -import org.apache.mina.codec.StatelessProtocolDecoder; -import org.apache.mina.codec.delimited.ints.RawInt32; -import org.apache.mina.codec.delimited.ints.VarInt; - -/** - * Abstract class providing both encoding and decoding methods between a given - * type and ByteBuffers. - * - * <p> - * Transcoder is stateless class providing encoding and decoding facilities. - * Additionally this abstract requires two methods which allows to determine the - * size of a given message and to write it directly to a previously allocated - * ByteBuffer. - * </p> - * - * @param <INPUT> - * the type of the messages which will be encoded in ByteBuffers and - * decoded from ByteBuffers. - * - * @author <a href="http://mina.apache.org">Apache MINA Project</a> - */ -public abstract class ByteBufferDecoder<INPUT> implements StatelessProtocolDecoder<ByteBuffer, INPUT> { - /** - * Being stateless, this method is left empty - * - * @see ProtocolDecoder#createDecoderState() - */ - @Override - public final Void createDecoderState() { - // stateless ! - return null; - } - - /** - * Decodes a message from a {@link ByteBuffer} - * - * <p> - * When a truncated input is given to this method it <b>may</b> return null. - * Not all decoder will be able to detect this issue and report it that way. - * Thanks to prefixing of messages, decoder will only receive appropriately - * sized ByteBuffers. - * </p> - * - * <p> - * n.b. The decoders used for the prefixing (i.e. {@link RawInt32} and - * {@link VarInt}) <b>have</b> to detect truncated ByteBuffers. - * </p> - * - * @param input - * data to be decoded as a TYPE message - * @return the decoded message on success, null otherwise - * - * @throws ProtocolDecoderException - */ - public abstract INPUT decode(ByteBuffer input); - - /** - * Decodes a message from a {@link ByteBuffer} - * <p> - * The actual decoding needs to be implemented in the abstract method - * {@link ByteBufferDecoder#decode(ByteBuffer)} - * </p> - */ - @Override - public final INPUT decode(ByteBuffer input, Void context) { - return decode(input); - } - - /** - * Being stateless, this method is left empty - * - * @see ProtocolDecoder#finishDecode(Object) - */ - @Override - public final void finishDecode(Void context) { - // stateless ! - } - -} http://git-wip-us.apache.org/repos/asf/mina/blob/ed496202/codec/src/main/java/org/apache/mina/codec/delimited/IoBufferDecoder.java ---------------------------------------------------------------------- diff --git a/codec/src/main/java/org/apache/mina/codec/delimited/IoBufferDecoder.java b/codec/src/main/java/org/apache/mina/codec/delimited/IoBufferDecoder.java new file mode 100644 index 0000000..416244a --- /dev/null +++ b/codec/src/main/java/org/apache/mina/codec/delimited/IoBufferDecoder.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.mina.codec.delimited; + +import java.nio.ByteBuffer; + +import org.apache.mina.codec.IoBuffer; +import org.apache.mina.codec.ProtocolDecoder; +import org.apache.mina.codec.ProtocolDecoderException; +import org.apache.mina.codec.StatelessProtocolDecoder; +import org.apache.mina.codec.delimited.ints.RawInt32; +import org.apache.mina.codec.delimited.ints.VarInt; + +/** + * Abstract class providing both encoding and decoding methods between a given + * type and ByteBuffers. + * + * <p> + * Transcoder is stateless class providing encoding and decoding facilities. + * Additionally this abstract requires two methods which allows to determine the + * size of a given message and to write it directly to a previously allocated + * ByteBuffer. + * </p> + * + * @param <INPUT> + * the type of the messages which will be encoded in ByteBuffers and + * decoded from ByteBuffers. + * + * @author <a href="http://mina.apache.org">Apache MINA Project</a> + */ +public abstract class IoBufferDecoder<INPUT> implements StatelessProtocolDecoder<IoBuffer, INPUT> { + /** + * Being stateless, this method is left empty + * + * @see ProtocolDecoder#createDecoderState() + */ + @Override + public final Void createDecoderState() { + // stateless ! + return null; + } + + /** + * Decodes a message from a {@link IoBuffer} + * + * <p> + * When a truncated input is given to this method it <b>may</b> return null. + * Not all decoder will be able to detect this issue and report it that way. + * Thanks to prefixing of messages, decoder will only receive appropriately + * sized ByteBuffers. + * </p> + * + * <p> + * n.b. The decoders used for the prefixing (i.e. {@link RawInt32} and + * {@link VarInt}) <b>have</b> to detect truncated ByteBuffers. + * </p> + * + * @param input + * data to be decoded as a TYPE message + * @return the decoded message on success, null otherwise + * + * @throws ProtocolDecoderException + */ + public abstract INPUT decode(IoBuffer input); + + /** + * Decodes a message from a {@link ByteBuffer} + * <p> + * The actual decoding needs to be implemented in the abstract method + * {@link IoBufferDecoder#decode(ByteBuffer)} + * </p> + */ + @Override + public final INPUT decode(IoBuffer input, Void context) { + return decode(input); + } + + /** + * Being stateless, this method is left empty + * + * @see ProtocolDecoder#finishDecode(Object) + */ + @Override + public final void finishDecode(Void context) { + // stateless ! + } + +} http://git-wip-us.apache.org/repos/asf/mina/blob/ed496202/codec/src/main/java/org/apache/mina/codec/delimited/SizePrefixedDecoder.java ---------------------------------------------------------------------- diff --git a/codec/src/main/java/org/apache/mina/codec/delimited/SizePrefixedDecoder.java b/codec/src/main/java/org/apache/mina/codec/delimited/SizePrefixedDecoder.java index 73eccf2..ffd701a 100644 --- a/codec/src/main/java/org/apache/mina/codec/delimited/SizePrefixedDecoder.java +++ b/codec/src/main/java/org/apache/mina/codec/delimited/SizePrefixedDecoder.java @@ -19,15 +19,14 @@ */ package org.apache.mina.codec.delimited; -import java.nio.ByteBuffer; - +import org.apache.mina.codec.IoBuffer; import org.apache.mina.codec.ProtocolDecoder; /** * * @author <a href="http://mina.apache.org">Apache MINA Project</a> */ -public class SizePrefixedDecoder<OUT> implements ProtocolDecoder<ByteBuffer, OUT, SizePrefixedDecoder.MutableInt> { +public class SizePrefixedDecoder<OUT> implements ProtocolDecoder<IoBuffer, OUT, SizePrefixedDecoder.MutableInt> { /** * A mutable {@link Integer} wrapper. @@ -83,11 +82,11 @@ public class SizePrefixedDecoder<OUT> implements ProtocolDecoder<ByteBuffer, OUT } } - private final ByteBufferDecoder<Integer> sizeDecoder; + private final IoBufferDecoder<Integer> sizeDecoder; - private final ByteBufferDecoder<OUT> payloadDecoder; + private final IoBufferDecoder<OUT> payloadDecoder; - public SizePrefixedDecoder(ByteBufferDecoder<Integer> sizeDecoder, ByteBufferDecoder<OUT> payloadDecoder) { + public SizePrefixedDecoder(IoBufferDecoder<Integer> sizeDecoder, IoBufferDecoder<OUT> payloadDecoder) { super(); this.sizeDecoder = sizeDecoder; this.payloadDecoder = payloadDecoder; @@ -100,7 +99,7 @@ public class SizePrefixedDecoder<OUT> implements ProtocolDecoder<ByteBuffer, OUT } @Override - public OUT decode(ByteBuffer input, MutableInt nextBlockSize) { + public OUT decode(IoBuffer input, MutableInt nextBlockSize) { OUT output = null; if (nextBlockSize.getValue() == null) { @@ -108,7 +107,7 @@ public class SizePrefixedDecoder<OUT> implements ProtocolDecoder<ByteBuffer, OUT } if (nextBlockSize.isDefined() && (input.remaining() >= nextBlockSize.getValue())) { - ByteBuffer buffer = input.slice(); + IoBuffer buffer = input.slice(); buffer.limit(buffer.position() + nextBlockSize.getValue()); output = payloadDecoder.decode(buffer); http://git-wip-us.apache.org/repos/asf/mina/blob/ed496202/codec/src/main/java/org/apache/mina/codec/delimited/ints/IntTranscoder.java ---------------------------------------------------------------------- diff --git a/codec/src/main/java/org/apache/mina/codec/delimited/ints/IntTranscoder.java b/codec/src/main/java/org/apache/mina/codec/delimited/ints/IntTranscoder.java new file mode 100644 index 0000000..35a145c --- /dev/null +++ b/codec/src/main/java/org/apache/mina/codec/delimited/ints/IntTranscoder.java @@ -0,0 +1,10 @@ +package org.apache.mina.codec.delimited.ints; + +import org.apache.mina.codec.delimited.ByteBufferEncoder; +import org.apache.mina.codec.delimited.IoBufferDecoder; + +public interface IntTranscoder { + IoBufferDecoder<Integer> getDecoder(); + + ByteBufferEncoder<Integer> getEncoder(); +} http://git-wip-us.apache.org/repos/asf/mina/blob/ed496202/codec/src/main/java/org/apache/mina/codec/delimited/ints/RawInt32.java ---------------------------------------------------------------------- diff --git a/codec/src/main/java/org/apache/mina/codec/delimited/ints/RawInt32.java b/codec/src/main/java/org/apache/mina/codec/delimited/ints/RawInt32.java index 6767a33..f650a58 100644 --- a/codec/src/main/java/org/apache/mina/codec/delimited/ints/RawInt32.java +++ b/codec/src/main/java/org/apache/mina/codec/delimited/ints/RawInt32.java @@ -19,11 +19,13 @@ */ package org.apache.mina.codec.delimited.ints; +import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; +import java.nio.ByteOrder; -import org.apache.mina.codec.ProtocolDecoderException; -import org.apache.mina.codec.delimited.ByteBufferDecoder; +import org.apache.mina.codec.IoBuffer; import org.apache.mina.codec.delimited.ByteBufferEncoder; +import org.apache.mina.codec.delimited.IoBufferDecoder; /** * @@ -105,45 +107,55 @@ import org.apache.mina.codec.delimited.ByteBufferEncoder; * * @author <a href="http://mina.apache.org">Apache MINA Project</a> */ -public class RawInt32 { - // this class should not be instanciated - private RawInt32() { +/* + * About the suppression of warnings: + * This class contains a lot of bit-shifting, logical and/or operations order to handle + * VarInt conversions. The code contains a lot of hard-coded integer that tools like + * Sonar classify as "magic numbers". Using final static variables for all of them + * would have resulted in a code less readable. + * The "all" scope is too generic, but Sonar doesn't not handle properly others scopes + * like "MagicNumber" (Sonar 3.6 - 03July2013) + */ +@SuppressWarnings("all") +public final class RawInt32 implements IntTranscoder { + private final ByteOrder bo; + + public RawInt32(ByteOrder bo) { + super(); + this.bo = bo == null ? ByteOrder.BIG_ENDIAN : bo; + } + + @Override + public IoBufferDecoder<Integer> getDecoder() { + return new Decoder(); + } + + @Override + public ByteBufferEncoder<Integer> getEncoder() { + return new Encoder(); } + private static final int BYTE_MASK = 0xff; + /** * Documentation available in the {@link RawInt32} enclosing class. * * @author <a href="http://mina.apache.org">Apache MINA Project</a> * */ - public static class Decoder extends ByteBufferDecoder<Integer> { - - private Endianness endianness; - - public Decoder(Endianness endianness) { - super(); - this.endianness = endianness; - } + private class Decoder extends IoBufferDecoder<Integer> { @Override - public Integer decode(ByteBuffer input) { + public Integer decode(IoBuffer input) { if (input.remaining() < 4) { return null; } - if (endianness == Endianness.BIG) { - if ((input.get(0) & 0x80) != 0) { - throw new ProtocolDecoderException("Not the big endian representation of a signed int32"); - } - return ((input.get() & 0xff) << 24) | ((input.get() & 0xff) << 16) | ((input.get() & 0xff) << 8) - | ((input.get() & 0xff)); - } else { - if ((input.get(3) & 0x80) != 0) { - throw new ProtocolDecoderException("Not the small endian representation of a signed int32"); - } - return ((input.get() & 0xff)) | ((input.get() & 0xff) << 8) | ((input.get() & 0xff) << 16) - | ((input.get() & 0xff) << 24); + int out = 0; + for (int i = 0; i < 32; i += 8) { + out |= (input.get() & 0xff) << (bo == ByteOrder.BIG_ENDIAN ? 24 - i : i); } + return out; } } @@ -153,33 +165,17 @@ public class RawInt32 { * @author <a href="http://mina.apache.org">Apache MINA Project</a> * */ - public static class Encoder extends ByteBufferEncoder<Integer> { - - private final Endianness endianness; - - public Encoder(Endianness endianness) { - super(); - this.endianness = endianness; - } + private class Encoder extends ByteBufferEncoder<Integer> { @Override public void writeTo(Integer message, ByteBuffer buffer) { - // VarInts don't support negative values - if (message < 0) { - message = 0; + + if (buffer.remaining() < 4) { + throw new BufferUnderflowException(); } - if (endianness == Endianness.BIG) { - buffer.put((byte) (0xff & (message >> 24))); - buffer.put((byte) (0xff & (message >> 16))); - buffer.put((byte) (0xff & (message >> 8))); - buffer.put((byte) (0xff & (message))); - } else { - buffer.put((byte) (0xff & (message))); - buffer.put((byte) (0xff & (message >> 8))); - buffer.put((byte) (0xff & (message >> 16))); - buffer.put((byte) (0xff & (message >> 24))); + for (int i = 0; i < 32; i += 8) { + buffer.put((byte) (message >> (bo == ByteOrder.BIG_ENDIAN ? 24 - i : i))); } - } @Override @@ -188,17 +184,4 @@ public class RawInt32 { } } - - /** - * - * This enumeration is used to select the endianness of the dncoder and the - * decoder class. - * - * Documentation available in the {@link RawInt32} enclosing class. - * - * @author <a href="http://mina.apache.org">Apache MINA Project</a> - */ - public enum Endianness { - BIG, LITTLE - } } http://git-wip-us.apache.org/repos/asf/mina/blob/ed496202/codec/src/main/java/org/apache/mina/codec/delimited/ints/VarInt.java ---------------------------------------------------------------------- diff --git a/codec/src/main/java/org/apache/mina/codec/delimited/ints/VarInt.java b/codec/src/main/java/org/apache/mina/codec/delimited/ints/VarInt.java index 625afeb..8102e6f 100644 --- a/codec/src/main/java/org/apache/mina/codec/delimited/ints/VarInt.java +++ b/codec/src/main/java/org/apache/mina/codec/delimited/ints/VarInt.java @@ -22,9 +22,10 @@ package org.apache.mina.codec.delimited.ints; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; +import org.apache.mina.codec.IoBuffer; import org.apache.mina.codec.ProtocolDecoderException; -import org.apache.mina.codec.delimited.ByteBufferDecoder; import org.apache.mina.codec.delimited.ByteBufferEncoder; +import org.apache.mina.codec.delimited.IoBufferDecoder; /** * Class providing a variable length representation of integers. @@ -80,9 +81,26 @@ import org.apache.mina.codec.delimited.ByteBufferEncoder; * * @author <a href="http://mina.apache.org">Apache MINA Project</a> */ -public class VarInt { - // this class should not be instanciated - private VarInt() { +/* + * About the suppression of warnings: + * This class contains a lot of bit-shifting, logical and/or operations order to handle + * VarInt conversions. The code contains a lot of hard-coded integer that tools like + * Sonar classify as "magic numbers". Using final static variables for all of them + * would have resulted in a code less readable. + * The "all" scope is too generic, but Sonar doesn't not handle properly others scopes + * like "MagicNumber" (Sonar 3.6 - 03July2013) + */ +@SuppressWarnings("all") +public final class VarInt implements IntTranscoder { + + @Override + public IoBufferDecoder<Integer> getDecoder() { + return new Decoder(); + } + + @Override + public ByteBufferEncoder<Integer> getEncoder() { + return new Encoder(); } /** @@ -91,29 +109,45 @@ public class VarInt { * @author <a href="http://mina.apache.org">Apache MINA Project</a> * */ - public static class Decoder extends ByteBufferDecoder<Integer> { + private class Decoder extends IoBufferDecoder<Integer> { @Override - public Integer decode(ByteBuffer input) { + public Integer decode(IoBuffer input) { int origpos = input.position(); - int size = 0; try { - for (int i = 0;; i += 7) { - byte tmp = input.get(); - - if ((tmp & 0x80) == 0 && (i != 4 * 7 || tmp < 1 << 3)) { - return size | (tmp << i); - } else if (i < 4 * 7) { - size |= (tmp & 0x7f) << i; + byte tmp = input.get(); + if (tmp >= 0) { + return (int) tmp; + } + int result = tmp & 0x7f; + if ((tmp = input.get()) >= 0) { + result |= tmp << 7; + } else { + result |= (tmp & 0x7f) << 7; + if ((tmp = input.get()) >= 0) { + result |= tmp << 14; } else { - throw new ProtocolDecoderException("Not the varint representation of a signed int32"); + result |= (tmp & 0x7f) << 14; + if ((tmp = input.get()) >= 0) { + result |= tmp << 21; + } else { + result |= (tmp & 0x7f) << 21; + + // check that there are at most 3 significant bits available + if (((tmp = input.get()) & ~0x7) == 0) { + result |= tmp << 28; + } else { + throw new ProtocolDecoderException("Not the varint representation of a signed int32"); + } + } } } + return result; + } catch (BufferUnderflowException bue) { input.position(origpos); } - return null; } } @@ -124,33 +158,41 @@ public class VarInt { * @author <a href="http://mina.apache.org">Apache MINA Project</a> * */ - public static class Encoder extends ByteBufferEncoder<Integer> { + private class Encoder extends ByteBufferEncoder<Integer> { @Override public void writeTo(Integer message, ByteBuffer buffer) { - int value = message; - // VarInts don't support negative values - if (value < 0) { - value = 0; - } + int value = Math.max(0,message); - while (value > 0x7f) { - buffer.put((byte) ((value & 0x7f) | 0x80)); - value >>= 7; + while (true) { + if ((value & ~0x7F) == 0) { + buffer.put((byte) value); + return; + } else { + buffer.put((byte) ((value & 0x7F) | 0x80)); + value >>>= 7; + } } - buffer.put((byte) value); } @Override - public int getEncodedSize(Integer message) { - if (message < 1) { + public int getEncodedSize(Integer value) { + if ((value & (0xffffffff << 7)) == 0) { return 1; - } else { - int log2 = 32 - Integer.numberOfLeadingZeros(message); - return (log2 + 6) / 7; } + if ((value & (0xffffffff << 14)) == 0) { + return 2; + } + if ((value & (0xffffffff << 21)) == 0) { + return 3; + } + if ((value & (0xffffffff << 28)) == 0) { + return 4; + } + return 5; } + } } http://git-wip-us.apache.org/repos/asf/mina/blob/ed496202/codec/src/main/java/org/apache/mina/codec/delimited/serialization/JavaNativeMessageDecoder.java ---------------------------------------------------------------------- diff --git a/codec/src/main/java/org/apache/mina/codec/delimited/serialization/JavaNativeMessageDecoder.java b/codec/src/main/java/org/apache/mina/codec/delimited/serialization/JavaNativeMessageDecoder.java index d7cc44d..f05882d 100644 --- a/codec/src/main/java/org/apache/mina/codec/delimited/serialization/JavaNativeMessageDecoder.java +++ b/codec/src/main/java/org/apache/mina/codec/delimited/serialization/JavaNativeMessageDecoder.java @@ -21,24 +21,23 @@ package org.apache.mina.codec.delimited.serialization; import java.io.ObjectInputStream; import java.io.Serializable; -import java.nio.ByteBuffer; +import org.apache.mina.codec.IoBuffer; import org.apache.mina.codec.ProtocolDecoderException; -import org.apache.mina.codec.delimited.ByteBufferDecoder; -import org.apache.mina.util.ByteBufferInputStream; +import org.apache.mina.codec.delimited.IoBufferDecoder; /** * Decoder providing the built-in Java-deserialization. * * @author <a href="http://mina.apache.org">Apache MINA Project</a> */ -public class JavaNativeMessageDecoder<IN extends Serializable> extends ByteBufferDecoder<IN> { +public class JavaNativeMessageDecoder<IN extends Serializable> extends IoBufferDecoder<IN> { @SuppressWarnings("unchecked") @Override - public IN decode(final ByteBuffer input) { + public IN decode(final IoBuffer input) { try { - ObjectInputStream ois = new ObjectInputStream(new ByteBufferInputStream(input)); + ObjectInputStream ois = new ObjectInputStream(input.asInputStream()); IN s = (IN) ois.readObject(); ois.close(); return s; http://git-wip-us.apache.org/repos/asf/mina/blob/ed496202/codec/src/test/java/org/apache/mina/codec/delimited/ints/IntEncodingTest.java ---------------------------------------------------------------------- diff --git a/codec/src/test/java/org/apache/mina/codec/delimited/ints/IntEncodingTest.java b/codec/src/test/java/org/apache/mina/codec/delimited/ints/IntEncodingTest.java index f1c385c..019b44d 100644 --- a/codec/src/test/java/org/apache/mina/codec/delimited/ints/IntEncodingTest.java +++ b/codec/src/test/java/org/apache/mina/codec/delimited/ints/IntEncodingTest.java @@ -26,14 +26,15 @@ import static org.junit.Assert.fail; import java.nio.ByteBuffer; import java.util.Map; +import org.apache.mina.codec.IoBuffer; import org.apache.mina.codec.ProtocolDecoderException; -import org.apache.mina.codec.delimited.ByteBufferDecoder; import org.apache.mina.codec.delimited.ByteBufferEncoder; +import org.apache.mina.codec.delimited.IoBufferDecoder; import org.junit.Before; import org.junit.Test; /** - * A generic test class for {@link ByteBufferEncoder} and {@link ByteBufferDecoder} + * A generic test class for {@link ByteBufferEncoder} and {@link IoBufferDecoder} * * @author <a href="http://mina.apache.org">Apache MINA Project</a> */ @@ -41,9 +42,9 @@ public abstract class IntEncodingTest { protected ByteBufferEncoder<Integer> encoder; - protected ByteBufferDecoder<Integer> decoder; + protected IoBufferDecoder<Integer> decoder; - public abstract ByteBufferDecoder<Integer> newDecoderInstance(); + public abstract IoBufferDecoder<Integer> newDecoderInstance(); public abstract ByteBufferEncoder<Integer> newEncoderInstance(); @@ -61,10 +62,10 @@ public abstract class IntEncodingTest { public void testTruncatedValues() { for (int value : new int[] { 0, 1, 127, 128, 65536, 198649, Integer.MAX_VALUE }) { - ByteBuffer buffer = encoder.encode(value); + IoBuffer buffer = IoBuffer.wrap(encoder.encode(value)); for (int i = 0; i < buffer.remaining(); i++) { - ByteBuffer partialBuffer = buffer.slice(); + IoBuffer partialBuffer = buffer.slice(); partialBuffer.limit(partialBuffer.position() + i); try { assertNull(decoder.decode(partialBuffer)); @@ -81,7 +82,7 @@ public abstract class IntEncodingTest { ByteBuffer buffer = encoder.encode(value); try { - assertEquals(value, decoder.decode(buffer).intValue()); + assertEquals(value, decoder.decode(IoBuffer.wrap(buffer)).intValue()); } catch (ProtocolDecoderException e) { fail("Should not throw exception"); } @@ -96,7 +97,7 @@ public abstract class IntEncodingTest { for (int i = 1; i < 5; i++) { int size = buffer.remaining() + i; - ByteBuffer extendedBuffer = ByteBuffer.allocate(size); + IoBuffer extendedBuffer = IoBuffer.wrap(ByteBuffer.allocate(size)); int start = extendedBuffer.position(); extendedBuffer.put(buffer.slice()); extendedBuffer.position(start); @@ -118,7 +119,7 @@ public abstract class IntEncodingTest { for (Integer val : samples.keySet()) { assertEquals(samples.get(val), encoder.encode(val)); try { - assertEquals(val, decoder.decode(samples.get(val))); + assertEquals(val, decoder.decode(IoBuffer.wrap(samples.get(val)))); } catch (ProtocolDecoderException e) { fail("Should not throw exception"); } @@ -130,7 +131,7 @@ public abstract class IntEncodingTest { for (ByteBuffer buffer : getIllegalBuffers()) { try { - decoder.decode(buffer); + decoder.decode(IoBuffer.wrap(buffer)); fail("Should throw an overflow exception"); } catch (ProtocolDecoderException e) { // fine @@ -138,11 +139,11 @@ public abstract class IntEncodingTest { } } - @Test - public void testNegativeValues() { - ByteBuffer zero = encoder.encode(0); - for (int i : new int[] { -1, -127, Integer.MIN_VALUE }) { - assertEquals(zero, encoder.encode(i)); - } - } +// @Test +// public void testNegativeValues() { +// ByteBuffer zero = encoder.encode(0); +// for (int i : new int[] { -1, -127, Integer.MIN_VALUE }) { +// assertEquals(zero, encoder.encode(i)); +// } +// } } http://git-wip-us.apache.org/repos/asf/mina/blob/ed496202/codec/src/test/java/org/apache/mina/codec/delimited/ints/RawInt32BigEndianEncodingTest.java ---------------------------------------------------------------------- diff --git a/codec/src/test/java/org/apache/mina/codec/delimited/ints/RawInt32BigEndianEncodingTest.java b/codec/src/test/java/org/apache/mina/codec/delimited/ints/RawInt32BigEndianEncodingTest.java index 1f64ee1..858d17b 100644 --- a/codec/src/test/java/org/apache/mina/codec/delimited/ints/RawInt32BigEndianEncodingTest.java +++ b/codec/src/test/java/org/apache/mina/codec/delimited/ints/RawInt32BigEndianEncodingTest.java @@ -20,13 +20,14 @@ package org.apache.mina.codec.delimited.ints; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; -import org.apache.mina.codec.delimited.ByteBufferDecoder; import org.apache.mina.codec.delimited.ByteBufferEncoder; +import org.apache.mina.codec.delimited.IoBufferDecoder; /** * A {@link Int32Decoder} and {@link Int32Encoder} test in a big endian setup. @@ -36,13 +37,13 @@ import org.apache.mina.codec.delimited.ByteBufferEncoder; public class RawInt32BigEndianEncodingTest extends IntEncodingTest { @Override - public ByteBufferDecoder<Integer> newDecoderInstance() { - return new RawInt32.Decoder(RawInt32.Endianness.BIG); + public IoBufferDecoder<Integer> newDecoderInstance() { + return new RawInt32(ByteOrder.BIG_ENDIAN).getDecoder(); } @Override public ByteBufferEncoder<Integer> newEncoderInstance() { - return new RawInt32.Encoder(RawInt32.Endianness.BIG); + return new RawInt32(ByteOrder.BIG_ENDIAN).getEncoder(); } @Override @@ -57,7 +58,6 @@ public class RawInt32BigEndianEncodingTest extends IntEncodingTest { @Override public Iterable<ByteBuffer> getIllegalBuffers() { List<ByteBuffer> list = new LinkedList<ByteBuffer>(); - list.add(ByteBuffer.wrap(new byte[] { (byte) 0x80, 0, 0, 0 })); return list; } } http://git-wip-us.apache.org/repos/asf/mina/blob/ed496202/codec/src/test/java/org/apache/mina/codec/delimited/ints/RawInt32LittleEndianEncodingTest.java ---------------------------------------------------------------------- diff --git a/codec/src/test/java/org/apache/mina/codec/delimited/ints/RawInt32LittleEndianEncodingTest.java b/codec/src/test/java/org/apache/mina/codec/delimited/ints/RawInt32LittleEndianEncodingTest.java index fa2d07c..c486402 100644 --- a/codec/src/test/java/org/apache/mina/codec/delimited/ints/RawInt32LittleEndianEncodingTest.java +++ b/codec/src/test/java/org/apache/mina/codec/delimited/ints/RawInt32LittleEndianEncodingTest.java @@ -20,13 +20,14 @@ package org.apache.mina.codec.delimited.ints; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; -import org.apache.mina.codec.delimited.ByteBufferDecoder; import org.apache.mina.codec.delimited.ByteBufferEncoder; +import org.apache.mina.codec.delimited.IoBufferDecoder; /** * A {@link RawInt32.Encoder} and {@link RawInt32.Decoder} test in a little endian setup. @@ -36,13 +37,13 @@ import org.apache.mina.codec.delimited.ByteBufferEncoder; public class RawInt32LittleEndianEncodingTest extends IntEncodingTest { @Override - public ByteBufferDecoder<Integer> newDecoderInstance() { - return new RawInt32.Decoder(RawInt32.Endianness.LITTLE); + public IoBufferDecoder<Integer> newDecoderInstance() { + return new RawInt32(ByteOrder.LITTLE_ENDIAN).getDecoder(); } @Override public ByteBufferEncoder<Integer> newEncoderInstance() { - return new RawInt32.Encoder(RawInt32.Endianness.LITTLE); + return new RawInt32(ByteOrder.LITTLE_ENDIAN).getEncoder(); } @Override @@ -57,7 +58,6 @@ public class RawInt32LittleEndianEncodingTest extends IntEncodingTest { @Override public Iterable<ByteBuffer> getIllegalBuffers() { List<ByteBuffer> list = new LinkedList<ByteBuffer>(); - list.add(ByteBuffer.wrap(new byte[] { 0, 0, 0, (byte) 0x80 })); return list; } } http://git-wip-us.apache.org/repos/asf/mina/blob/ed496202/codec/src/test/java/org/apache/mina/codec/delimited/ints/VarIntEncodingTest.java ---------------------------------------------------------------------- diff --git a/codec/src/test/java/org/apache/mina/codec/delimited/ints/VarIntEncodingTest.java b/codec/src/test/java/org/apache/mina/codec/delimited/ints/VarIntEncodingTest.java index 694773a..e0cf6d8 100644 --- a/codec/src/test/java/org/apache/mina/codec/delimited/ints/VarIntEncodingTest.java +++ b/codec/src/test/java/org/apache/mina/codec/delimited/ints/VarIntEncodingTest.java @@ -25,7 +25,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; -import org.apache.mina.codec.delimited.ByteBufferDecoder; +import org.apache.mina.codec.delimited.IoBufferDecoder; import org.apache.mina.codec.delimited.ByteBufferEncoder; /** @@ -36,13 +36,13 @@ import org.apache.mina.codec.delimited.ByteBufferEncoder; public class VarIntEncodingTest extends IntEncodingTest { @Override - public ByteBufferDecoder<Integer> newDecoderInstance() { - return new VarInt.Decoder(); + public IoBufferDecoder<Integer> newDecoderInstance() { + return new VarInt().getDecoder(); } @Override public ByteBufferEncoder<Integer> newEncoderInstance() { - return new VarInt.Encoder(); + return new VarInt().getEncoder(); } @Override http://git-wip-us.apache.org/repos/asf/mina/blob/ed496202/codec/src/test/java/org/apache/mina/codec/delimited/serialization/GenericSerializerTest.java ---------------------------------------------------------------------- diff --git a/codec/src/test/java/org/apache/mina/codec/delimited/serialization/GenericSerializerTest.java b/codec/src/test/java/org/apache/mina/codec/delimited/serialization/GenericSerializerTest.java index b2c4086..487c9bd 100644 --- a/codec/src/test/java/org/apache/mina/codec/delimited/serialization/GenericSerializerTest.java +++ b/codec/src/test/java/org/apache/mina/codec/delimited/serialization/GenericSerializerTest.java @@ -24,18 +24,19 @@ import static org.junit.Assert.assertEquals; import java.nio.ByteBuffer; import java.util.List; -import org.apache.mina.codec.delimited.ByteBufferDecoder; +import org.apache.mina.codec.IoBuffer; import org.apache.mina.codec.delimited.ByteBufferEncoder; +import org.apache.mina.codec.delimited.IoBufferDecoder; import org.junit.Test; /** - * A {@link ByteBufferEncoder} and {@link ByteBufferDecoder} test. + * A {@link ByteBufferEncoder} and {@link IoBufferDecoder} test. * * @author <a href="http://mina.apache.org">Apache MINA Project</a> */ public abstract class GenericSerializerTest<T> { - public abstract ByteBufferDecoder<T> getDecoder() throws Exception; + public abstract IoBufferDecoder<T> getDecoder() throws Exception; public abstract ByteBufferEncoder<T> getEncoder() throws Exception; @@ -43,24 +44,24 @@ public abstract class GenericSerializerTest<T> { @Test public void testSerialization() throws Exception { - ByteBufferDecoder<T> decoder = getDecoder(); + IoBufferDecoder<T> decoder = getDecoder(); ByteBufferEncoder<T> encoder = getEncoder(); for (T object : getObjects()) { - assertEquals(object, decoder.decode(encoder.encode(object))); + assertEquals(object, decoder.decode(IoBuffer.wrap(encoder.encode(object)))); } } @Test public void testEncodedSize() throws Exception { - ByteBufferDecoder<T> decoder = getDecoder(); + IoBufferDecoder<T> decoder = getDecoder(); ByteBufferEncoder<T> encoder = getEncoder(); for (T object : getObjects()) { int size = encoder.getEncodedSize(object); ByteBuffer out = ByteBuffer.allocate(size); - encoder.writeTo(object, out); + encoder.writeTo(object, out); assertEquals(size, out.position()); out.position(0); - assertEquals(object, decoder.decode(out)); + assertEquals(object, decoder.decode(IoBuffer.wrap(out))); } } } http://git-wip-us.apache.org/repos/asf/mina/blob/ed496202/codec/src/test/java/org/apache/mina/codec/delimited/serialization/JavaNativeTest.java ---------------------------------------------------------------------- diff --git a/codec/src/test/java/org/apache/mina/codec/delimited/serialization/JavaNativeTest.java b/codec/src/test/java/org/apache/mina/codec/delimited/serialization/JavaNativeTest.java index 0e7257c..b2d8bed 100644 --- a/codec/src/test/java/org/apache/mina/codec/delimited/serialization/JavaNativeTest.java +++ b/codec/src/test/java/org/apache/mina/codec/delimited/serialization/JavaNativeTest.java @@ -23,7 +23,7 @@ import java.io.Serializable; import java.util.LinkedList; import java.util.List; -import org.apache.mina.codec.delimited.ByteBufferDecoder; +import org.apache.mina.codec.delimited.IoBufferDecoder; import org.apache.mina.codec.delimited.ByteBufferEncoder; /** @@ -98,7 +98,7 @@ public class JavaNativeTest extends GenericSerializerTest<JavaNativeTest.TestBea } @Override - public ByteBufferDecoder<TestBean> getDecoder() throws Exception { + public IoBufferDecoder<TestBean> getDecoder() throws Exception { return new JavaNativeMessageDecoder<TestBean>(); }
