diff --git a/README.adoc b/README.adoc index a35db16..75e2dcd 100644 --- a/README.adoc +++ b/README.adoc @@ -4,5 +4,5 @@ * License: Apache-2.0 License * Required Java version: Java 11 * Maven coordinates: -** `io.netty.contrib:netty-codec-redis:5.0.0.Final-SNAPSHOT` +** `io.netty.contrib:netty-codec-redis:4.1.92.Final-SNAPSHOT` diff --git a/benchmarks/pom.xml b/benchmarks/pom.xml index 6c5f7da..6262917 100644 --- a/benchmarks/pom.xml +++ b/benchmarks/pom.xml @@ -7,14 +7,14 @@ io.netty.contrib netty-codec-redis-parent - 5.0.0.Final-SNAPSHOT + 4.1.92.Final-SNAPSHOT netty-codec-redis-benchmarks ${parent.version} - 1.33 + 1.36 @@ -44,4 +44,4 @@ ${jmh.version} - \ No newline at end of file + diff --git a/benchmarks/src/main/java/io/netty/contrib/microbenchmarks/redis/RedisEncoderBenchmark.java b/benchmarks/src/main/java/io/netty/contrib/microbenchmarks/redis/RedisEncoderBenchmark.java index b9330fc..176a971 100644 --- a/benchmarks/src/main/java/io/netty/contrib/microbenchmarks/redis/RedisEncoderBenchmark.java +++ b/benchmarks/src/main/java/io/netty/contrib/microbenchmarks/redis/RedisEncoderBenchmark.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance @@ -15,17 +15,9 @@ */ package io.netty.contrib.microbenchmarks.redis; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.PooledByteBufAllocator; -import io.netty.buffer.Unpooled; -import io.netty.buffer.UnpooledByteBufAllocator; -import io.netty.channel.ChannelHandlerContext; -import io.netty.contrib.handler.codec.redis.ArrayRedisMessage; -import io.netty.contrib.handler.codec.redis.FullBulkStringRedisMessage; -import io.netty.contrib.handler.codec.redis.RedisEncoder; -import io.netty.contrib.handler.codec.redis.RedisMessage; -import io.netty.microbench.channel.EmbeddedChannelWriteReleaseHandlerContext; -import io.netty.util.concurrent.Future; +import java.util.ArrayList; +import java.util.List; + import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Level; @@ -38,15 +30,25 @@ import org.openjdk.jmh.annotations.Threads; import org.openjdk.jmh.annotations.Warmup; -import java.util.ArrayList; -import java.util.List; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.PooledByteBufAllocator; +import io.netty.buffer.Unpooled; +import io.netty.buffer.UnpooledByteBufAllocator; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPromise; +import io.netty.contrib.handler.codec.redis.ArrayRedisMessage; +import io.netty.contrib.handler.codec.redis.FullBulkStringRedisMessage; +import io.netty.contrib.handler.codec.redis.RedisEncoder; +import io.netty.contrib.handler.codec.redis.RedisMessage; +import io.netty.microbench.channel.EmbeddedChannelWriteReleaseHandlerContext; +import io.netty.microbench.util.AbstractMicrobenchmark; @State(Scope.Benchmark) @Fork(1) @Threads(1) @Warmup(iterations = 5) @Measurement(iterations = 5) -public class RedisEncoderBenchmark { +public class RedisEncoderBenchmark extends AbstractMicrobenchmark { private RedisEncoder encoder; private ByteBuf content; private ChannelHandlerContext context; @@ -55,6 +57,9 @@ public class RedisEncoderBenchmark { @Param({ "true", "false" }) public boolean pooledAllocator; + @Param({ "true", "false" }) + public boolean voidPromise; + @Param({ "50", "200", "1000" }) public int arraySize; @@ -65,7 +70,7 @@ public void setup() { content.writeBytes(bytes); ByteBuf testContent = Unpooled.unreleasableBuffer(content.asReadOnly()); - List rList = new ArrayList<>(arraySize); + List rList = new ArrayList(arraySize); for (int i = 0; i < arraySize; ++i) { rList.add(new FullBulkStringRedisMessage(testContent)); } @@ -75,20 +80,23 @@ public void setup() { UnpooledByteBufAllocator.DEFAULT, encoder) { @Override protected void handleException(Throwable t) { - throw new AssertionError("Unexpected exception", t); + handleUnexpectedException(t); } }; } @TearDown(Level.Trial) - public void tearDown() { - redisArray.release(); + public void teardown() { content.release(); content = null; } @Benchmark - public Future writeArray() { - return encoder.write(context, redisArray.retain()); + public void writeArray() throws Exception { + encoder.write(context, redisArray.retain(), newPromise()); + } + + private ChannelPromise newPromise() { + return voidPromise ? context.voidPromise() : context.newPromise(); } } diff --git a/benchmarks/src/main/java/io/netty/contrib/microbenchmarks/redis/package-info.java b/benchmarks/src/main/java/io/netty/contrib/microbenchmarks/redis/package-info.java index 5bafa73..e92a380 100644 --- a/benchmarks/src/main/java/io/netty/contrib/microbenchmarks/redis/package-info.java +++ b/benchmarks/src/main/java/io/netty/contrib/microbenchmarks/redis/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance @@ -14,6 +14,6 @@ * under the License. */ /** - * Benchmarks for {@link io.netty.contrib.handler.codec.redis}. + * Benchmarks for {@link io.netty.handler.codec.redis}. */ package io.netty.contrib.microbenchmarks.redis; diff --git a/codec-redis/pom.xml b/codec-redis/pom.xml index b8f257c..9ccc064 100644 --- a/codec-redis/pom.xml +++ b/codec-redis/pom.xml @@ -7,10 +7,10 @@ io.netty.contrib netty-codec-redis-parent - 5.0.0.Final-SNAPSHOT + 4.1.92.Final-SNAPSHOT - codec-redis + netty-codec-redis ${parent.version} Netty/Codec/Redis jar @@ -52,4 +52,4 @@ test - \ No newline at end of file + diff --git a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/AbstractStringRedisMessage.java b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/AbstractStringRedisMessage.java index dd814d6..f4d73ee 100644 --- a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/AbstractStringRedisMessage.java +++ b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/AbstractStringRedisMessage.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project 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 @@ -12,10 +12,10 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ -package io.netty.contrib.handler.codec.redis; -import static java.util.Objects.requireNonNull; +package io.netty.contrib.handler.codec.redis; +import io.netty.util.internal.ObjectUtil; import io.netty.util.internal.StringUtil; import io.netty.util.internal.UnstableApi; @@ -28,7 +28,7 @@ public abstract class AbstractStringRedisMessage implements RedisMessage { private final String content; AbstractStringRedisMessage(String content) { - this.content = requireNonNull(content, "content"); + this.content = ObjectUtil.checkNotNull(content, "content"); } /** @@ -48,4 +48,5 @@ public String toString() { .append(content) .append(']').toString(); } + } diff --git a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/ArrayHeaderRedisMessage.java b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/ArrayHeaderRedisMessage.java index 1bd5a7f..86c3a5e 100644 --- a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/ArrayHeaderRedisMessage.java +++ b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/ArrayHeaderRedisMessage.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project 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 @@ -12,6 +12,7 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ + package io.netty.contrib.handler.codec.redis; import io.netty.util.internal.StringUtil; @@ -30,7 +31,7 @@ public class ArrayHeaderRedisMessage implements RedisMessage { */ public ArrayHeaderRedisMessage(long length) { if (length < RedisConstants.NULL_VALUE) { - throw new RedisCodecException("length: " + length + " (expected: >= " + RedisConstants.NULL_VALUE + ')'); + throw new RedisCodecException("length: " + length + " (expected: >= " + RedisConstants.NULL_VALUE + ")"); } this.length = length; } diff --git a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/ArrayRedisMessage.java b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/ArrayRedisMessage.java index df48f39..81480c3 100644 --- a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/ArrayRedisMessage.java +++ b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/ArrayRedisMessage.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project 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 @@ -12,18 +12,18 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ + package io.netty.contrib.handler.codec.redis; -import static java.util.Objects.requireNonNull; +import java.util.Collections; +import java.util.List; import io.netty.util.AbstractReferenceCounted; import io.netty.util.ReferenceCountUtil; +import io.netty.util.internal.ObjectUtil; import io.netty.util.internal.StringUtil; import io.netty.util.internal.UnstableApi; -import java.util.Collections; -import java.util.List; - /** * Arrays of RESP. */ @@ -43,7 +43,7 @@ private ArrayRedisMessage() { */ public ArrayRedisMessage(List children) { // do not retain here. children are already retained when created. - this.children = requireNonNull(children, "children"); + this.children = ObjectUtil.checkNotNull(children, "children"); } /** @@ -173,4 +173,5 @@ public String toString() { return "EmptyArrayRedisMessage"; } }; + } diff --git a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/BulkStringHeaderRedisMessage.java b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/BulkStringHeaderRedisMessage.java index c579b6f..183c0c4 100644 --- a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/BulkStringHeaderRedisMessage.java +++ b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/BulkStringHeaderRedisMessage.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project 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 @@ -12,6 +12,7 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ + package io.netty.contrib.handler.codec.redis; import io.netty.util.internal.UnstableApi; diff --git a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/BulkStringRedisContent.java b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/BulkStringRedisContent.java index 4248efe..9e5ff4c 100644 --- a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/BulkStringRedisContent.java +++ b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/BulkStringRedisContent.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project 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 @@ -12,6 +12,7 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ + package io.netty.contrib.handler.codec.redis; import io.netty.buffer.ByteBuf; diff --git a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/DefaultBulkStringRedisContent.java b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/DefaultBulkStringRedisContent.java index d396c4c..01952ad 100644 --- a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/DefaultBulkStringRedisContent.java +++ b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/DefaultBulkStringRedisContent.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project 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 @@ -12,6 +12,7 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ + package io.netty.contrib.handler.codec.redis; import io.netty.buffer.ByteBuf; diff --git a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/DefaultLastBulkStringRedisContent.java b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/DefaultLastBulkStringRedisContent.java index a50e5d8..80d4993 100644 --- a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/DefaultLastBulkStringRedisContent.java +++ b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/DefaultLastBulkStringRedisContent.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project 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 @@ -12,6 +12,7 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ + package io.netty.contrib.handler.codec.redis; import io.netty.buffer.ByteBuf; diff --git a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/ErrorRedisMessage.java b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/ErrorRedisMessage.java index c3688f5..671a710 100644 --- a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/ErrorRedisMessage.java +++ b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/ErrorRedisMessage.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project 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 @@ -12,6 +12,7 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ + package io.netty.contrib.handler.codec.redis; import io.netty.util.internal.UnstableApi; @@ -30,4 +31,5 @@ public final class ErrorRedisMessage extends AbstractStringRedisMessage { public ErrorRedisMessage(String content) { super(content); } + } diff --git a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/FixedRedisMessagePool.java b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/FixedRedisMessagePool.java index 66f4770..6b6d7d4 100644 --- a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/FixedRedisMessagePool.java +++ b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/FixedRedisMessagePool.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project 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 @@ -12,8 +12,12 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ + package io.netty.contrib.handler.codec.redis; +import java.util.HashMap; +import java.util.Map; + import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.util.CharsetUtil; @@ -21,10 +25,6 @@ import io.netty.util.collection.LongObjectMap; import io.netty.util.internal.UnstableApi; -import java.util.EnumMap; -import java.util.HashMap; -import java.util.Map; - /** * A default fixed redis message pool. */ @@ -94,9 +94,9 @@ public String toString() { * Creates a {@link FixedRedisMessagePool} instance. */ private FixedRedisMessagePool() { - keyToSimpleStrings = new EnumMap(RedisReplyKey.class); - stringToSimpleStrings = new HashMap<>(RedisReplyKey.values().length, 1.0f); - byteBufToSimpleStrings = new HashMap<>(RedisReplyKey.values().length, 1.0f); + keyToSimpleStrings = new HashMap(RedisReplyKey.values().length, 1.0f); + stringToSimpleStrings = new HashMap(RedisReplyKey.values().length, 1.0f); + byteBufToSimpleStrings = new HashMap(RedisReplyKey.values().length, 1.0f); for (RedisReplyKey value : RedisReplyKey.values()) { ByteBuf key = Unpooled.unreleasableBuffer(Unpooled.wrappedBuffer( value.name().getBytes(CharsetUtil.UTF_8))).asReadOnly(); @@ -107,9 +107,9 @@ private FixedRedisMessagePool() { byteBufToSimpleStrings.put(key, message); } - keyToErrors = new EnumMap(RedisErrorKey.class); - stringToErrors = new HashMap<>(RedisErrorKey.values().length, 1.0f); - byteBufToErrors = new HashMap<>(RedisErrorKey.values().length, 1.0f); + keyToErrors = new HashMap(RedisErrorKey.values().length, 1.0f); + stringToErrors = new HashMap(RedisErrorKey.values().length, 1.0f); + byteBufToErrors = new HashMap(RedisErrorKey.values().length, 1.0f); for (RedisErrorKey value : RedisErrorKey.values()) { ByteBuf key = Unpooled.unreleasableBuffer(Unpooled.wrappedBuffer( value.toString().getBytes(CharsetUtil.UTF_8))).asReadOnly(); @@ -120,9 +120,9 @@ private FixedRedisMessagePool() { byteBufToErrors.put(key, message); } - byteBufToIntegers = new HashMap<>(SIZE_CACHED_INTEGER_NUMBER, 1.0f); - longToIntegers = new LongObjectHashMap<>(SIZE_CACHED_INTEGER_NUMBER, 1.0f); - longToByteBufs = new LongObjectHashMap<>(SIZE_CACHED_INTEGER_NUMBER, 1.0f); + byteBufToIntegers = new HashMap(SIZE_CACHED_INTEGER_NUMBER, 1.0f); + longToIntegers = new LongObjectHashMap(SIZE_CACHED_INTEGER_NUMBER, 1.0f); + longToByteBufs = new LongObjectHashMap(SIZE_CACHED_INTEGER_NUMBER, 1.0f); for (long value = MIN_CACHED_INTEGER_NUMBER; value < MAX_CACHED_INTEGER_NUMBER; value++) { byte[] keyBytes = RedisCodecUtil.longToAsciiBytes(value); ByteBuf keyByteBuf = Unpooled.unreleasableBuffer(Unpooled.wrappedBuffer(keyBytes)).asReadOnly(); diff --git a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/FullBulkStringRedisMessage.java b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/FullBulkStringRedisMessage.java index af616b9..e943153 100644 --- a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/FullBulkStringRedisMessage.java +++ b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/FullBulkStringRedisMessage.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project 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 @@ -12,6 +12,7 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ + package io.netty.contrib.handler.codec.redis; import io.netty.buffer.ByteBuf; diff --git a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/InlineCommandRedisMessage.java b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/InlineCommandRedisMessage.java index ab5e4cf..1049f3e 100644 --- a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/InlineCommandRedisMessage.java +++ b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/InlineCommandRedisMessage.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2018 The Netty Project * * The Netty Project 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 @@ -12,6 +12,7 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ + package io.netty.contrib.handler.codec.redis; import io.netty.util.internal.UnstableApi; @@ -30,4 +31,5 @@ public final class InlineCommandRedisMessage extends AbstractStringRedisMessage public InlineCommandRedisMessage(String content) { super(content); } + } diff --git a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/IntegerRedisMessage.java b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/IntegerRedisMessage.java index 1b91f4c..b0eec2a 100644 --- a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/IntegerRedisMessage.java +++ b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/IntegerRedisMessage.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project 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 @@ -12,6 +12,7 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ + package io.netty.contrib.handler.codec.redis; import io.netty.util.internal.StringUtil; diff --git a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/LastBulkStringRedisContent.java b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/LastBulkStringRedisContent.java index e290211..fedaec0 100644 --- a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/LastBulkStringRedisContent.java +++ b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/LastBulkStringRedisContent.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project 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 @@ -12,6 +12,7 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ + package io.netty.contrib.handler.codec.redis; import io.netty.buffer.ByteBuf; diff --git a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisArrayAggregator.java b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisArrayAggregator.java index 4843488..7ca1df0 100644 --- a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisArrayAggregator.java +++ b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisArrayAggregator.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project 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 @@ -12,19 +12,20 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ + package io.netty.contrib.handler.codec.redis; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.List; + import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.CodecException; import io.netty.handler.codec.MessageToMessageDecoder; import io.netty.util.ReferenceCountUtil; import io.netty.util.internal.UnstableApi; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Deque; -import java.util.List; - /** * Aggregates {@link RedisMessage} parts into {@link ArrayRedisMessage}. This decoder * should be used together with {@link RedisDecoder}. @@ -32,10 +33,10 @@ @UnstableApi public final class RedisArrayAggregator extends MessageToMessageDecoder { - private final Deque depths = new ArrayDeque<>(4); + private final Deque depths = new ArrayDeque(4); @Override - protected void decode(ChannelHandlerContext ctx, RedisMessage msg) throws Exception { + protected void decode(ChannelHandlerContext ctx, RedisMessage msg, List out) throws Exception { if (msg instanceof ArrayHeaderRedisMessage) { msg = decodeRedisArrayHeader((ArrayHeaderRedisMessage) msg); if (msg == null) { @@ -54,12 +55,12 @@ protected void decode(ChannelHandlerContext ctx, RedisMessage msg) throws Except msg = new ArrayRedisMessage(current.children); depths.pop(); } else { - // Not aggregated yet. Try next time. + // not aggregated yet. try next time. return; } } - ctx.fireChannelRead(msg); + out.add(msg); } private RedisMessage decodeRedisArrayHeader(ArrayHeaderRedisMessage header) { @@ -86,7 +87,7 @@ private static final class AggregateState { private final List children; AggregateState(int length) { this.length = length; - children = new ArrayList<>(length); + this.children = new ArrayList(length); } } } diff --git a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisBulkStringAggregator.java b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisBulkStringAggregator.java index 63bd248..b1a349b 100644 --- a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisBulkStringAggregator.java +++ b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisBulkStringAggregator.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project 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 @@ -12,6 +12,7 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ + package io.netty.contrib.handler.codec.redis; import io.netty.buffer.ByteBuf; diff --git a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisCodecException.java b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisCodecException.java index c55f883..52bfdfe 100644 --- a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisCodecException.java +++ b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisCodecException.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project 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 @@ -12,6 +12,7 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ + package io.netty.contrib.handler.codec.redis; import io.netty.handler.codec.CodecException; diff --git a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisCodecUtil.java b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisCodecUtil.java index 0b0abcc..d0c9154 100644 --- a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisCodecUtil.java +++ b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisCodecUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project 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 @@ -12,6 +12,7 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ + package io.netty.contrib.handler.codec.redis; import io.netty.util.CharsetUtil; @@ -34,7 +35,7 @@ static byte[] longToAsciiBytes(long value) { */ static short makeShort(char first, char second) { return PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? - (short) (second << 8 | first) : (short) (first << 8 | second); + (short) ((second << 8) | first) : (short) ((first << 8) | second); } /** @@ -43,10 +44,10 @@ static short makeShort(char first, char second) { static byte[] shortToBytes(short value) { byte[] bytes = new byte[2]; if (PlatformDependent.BIG_ENDIAN_NATIVE_ORDER) { - bytes[1] = (byte) (value >> 8 & 0xff); + bytes[1] = (byte) ((value >> 8) & 0xff); bytes[0] = (byte) (value & 0xff); } else { - bytes[0] = (byte) (value >> 8 & 0xff); + bytes[0] = (byte) ((value >> 8) & 0xff); bytes[1] = (byte) (value & 0xff); } return bytes; diff --git a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisConstants.java b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisConstants.java index 2d0f1d2..b5eb684 100644 --- a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisConstants.java +++ b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisConstants.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project 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 @@ -12,6 +12,7 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ + package io.netty.contrib.handler.codec.redis; /** diff --git a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisDecoder.java b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisDecoder.java index ceaf95d..a996545 100644 --- a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisDecoder.java +++ b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project 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 @@ -12,8 +12,11 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ + package io.netty.contrib.handler.codec.redis; +import java.util.List; + import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; @@ -92,7 +95,7 @@ public RedisDecoder(int maxInlineMessageLength, RedisMessagePool messagePool, bo } @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception { + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { try { for (;;) { switch (state) { @@ -102,22 +105,22 @@ protected void decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception { } break; case DECODE_INLINE: - if (!decodeInline(ctx, in)) { + if (!decodeInline(in, out)) { return; } break; case DECODE_LENGTH: - if (!decodeLength(ctx, in)) { + if (!decodeLength(in, out)) { return; } break; case DECODE_BULK_STRING_EOL: - if (!decodeBulkStringEndOfLine(ctx, in)) { + if (!decodeBulkStringEndOfLine(in, out)) { return; } break; case DECODE_BULK_STRING_CONTENT: - if (!decodeBulkStringContent(ctx, in)) { + if (!decodeBulkStringContent(in, out)) { return; } break; @@ -149,7 +152,7 @@ private boolean decodeType(ByteBuf in) throws Exception { return true; } - private boolean decodeInline(ChannelHandlerContext ctx, ByteBuf in) throws Exception { + private boolean decodeInline(ByteBuf in, List out) throws Exception { ByteBuf lineBytes = readLine(in); if (lineBytes == null) { if (in.readableBytes() > maxInlineMessageLength) { @@ -158,12 +161,12 @@ private boolean decodeInline(ChannelHandlerContext ctx, ByteBuf in) throws Excep } return false; } - ctx.fireChannelRead(newInlineRedisMessage(type, lineBytes)); + out.add(newInlineRedisMessage(type, lineBytes)); resetDecoder(); return true; } - private boolean decodeLength(ChannelHandlerContext ctx, ByteBuf in) throws Exception { + private boolean decodeLength(ByteBuf in, List out) throws Exception { ByteBuf lineByteBuf = readLine(in); if (lineByteBuf == null) { return false; @@ -174,7 +177,7 @@ private boolean decodeLength(ChannelHandlerContext ctx, ByteBuf in) throws Excep } switch (type) { case ARRAY_HEADER: - ctx.fireChannelRead(new ArrayHeaderRedisMessage(length)); + out.add(new ArrayHeaderRedisMessage(length)); resetDecoder(); return true; case BULK_STRING: @@ -183,41 +186,41 @@ private boolean decodeLength(ChannelHandlerContext ctx, ByteBuf in) throws Excep RedisConstants.REDIS_MESSAGE_MAX_LENGTH + ")"); } remainingBulkLength = (int) length; // range(int) is already checked. - return decodeBulkString(ctx, in); + return decodeBulkString(in, out); default: throw new RedisCodecException("bad type: " + type); } } - private boolean decodeBulkString(ChannelHandlerContext ctx, ByteBuf in) throws Exception { + private boolean decodeBulkString(ByteBuf in, List out) throws Exception { switch (remainingBulkLength) { case RedisConstants.NULL_VALUE: // $-1\r\n - ctx.fireChannelRead(FullBulkStringRedisMessage.NULL_INSTANCE); + out.add(FullBulkStringRedisMessage.NULL_INSTANCE); resetDecoder(); return true; case 0: state = State.DECODE_BULK_STRING_EOL; - return decodeBulkStringEndOfLine(ctx, in); + return decodeBulkStringEndOfLine(in, out); default: // expectedBulkLength is always positive. - ctx.fireChannelRead(new BulkStringHeaderRedisMessage(remainingBulkLength)); + out.add(new BulkStringHeaderRedisMessage(remainingBulkLength)); state = State.DECODE_BULK_STRING_CONTENT; - return decodeBulkStringContent(ctx, in); + return decodeBulkStringContent(in, out); } } // $0\r\n \r\n - private boolean decodeBulkStringEndOfLine(ChannelHandlerContext ctx, ByteBuf in) throws Exception { + private boolean decodeBulkStringEndOfLine(ByteBuf in, List out) throws Exception { if (in.readableBytes() < RedisConstants.EOL_LENGTH) { return false; } readEndOfLine(in); - ctx.fireChannelRead(FullBulkStringRedisMessage.EMPTY_INSTANCE); + out.add(FullBulkStringRedisMessage.EMPTY_INSTANCE); resetDecoder(); return true; } // ${expectedBulkLength}\r\n {data...}\r\n - private boolean decodeBulkStringContent(ChannelHandlerContext ctx, ByteBuf in) throws Exception { + private boolean decodeBulkStringContent(ByteBuf in, List out) throws Exception { final int readableBytes = in.readableBytes(); if (readableBytes == 0 || remainingBulkLength == 0 && readableBytes < RedisConstants.EOL_LENGTH) { return false; @@ -228,7 +231,7 @@ private boolean decodeBulkStringContent(ChannelHandlerContext ctx, ByteBuf in) t ByteBuf content = in.readSlice(remainingBulkLength); readEndOfLine(in); // Only call retain after readEndOfLine(...) as the method may throw an exception. - ctx.fireChannelRead(new DefaultLastBulkStringRedisContent(content.retain())); + out.add(new DefaultLastBulkStringRedisContent(content.retain())); resetDecoder(); return true; } @@ -236,7 +239,7 @@ private boolean decodeBulkStringContent(ChannelHandlerContext ctx, ByteBuf in) t // chunked write. int toRead = Math.min(remainingBulkLength, readableBytes); remainingBulkLength -= toRead; - ctx.fireChannelRead(new DefaultBulkStringRedisContent(in.readSlice(toRead).retain())); + out.add(new DefaultBulkStringRedisContent(in.readSlice(toRead).retain())); return true; } @@ -310,7 +313,7 @@ private static final class ToPositiveLongProcessor implements ByteProcessor { private long result; @Override - public boolean process(byte value) { + public boolean process(byte value) throws Exception { if (value < '0' || value > '9') { throw new RedisCodecException("bad byte in number: " + value); } diff --git a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisEncoder.java b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisEncoder.java index e0bf4e3..7920f88 100644 --- a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisEncoder.java +++ b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project 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 @@ -12,9 +12,10 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ + package io.netty.contrib.handler.codec.redis; -import static java.util.Objects.requireNonNull; +import java.util.List; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; @@ -22,10 +23,9 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.CodecException; import io.netty.handler.codec.MessageToMessageEncoder; +import io.netty.util.internal.ObjectUtil; import io.netty.util.internal.UnstableApi; -import java.util.List; - /** * Encodes {@link RedisMessage} into bytes following * RESP (REdis Serialization Protocol). @@ -47,7 +47,7 @@ public RedisEncoder() { * @param messagePool the predefined message pool. */ public RedisEncoder(RedisMessagePool messagePool) { - this.messagePool = requireNonNull(messagePool, "messagePool"); + this.messagePool = ObjectUtil.checkNotNull(messagePool, "messagePool"); } @Override diff --git a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisMessage.java b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisMessage.java index 8b00373..80860ac 100644 --- a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisMessage.java +++ b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisMessage.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project 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 @@ -12,6 +12,7 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ + package io.netty.contrib.handler.codec.redis; import io.netty.util.internal.UnstableApi; diff --git a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisMessagePool.java b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisMessagePool.java index ad0103b..4edda9c 100644 --- a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisMessagePool.java +++ b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisMessagePool.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project 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 @@ -12,6 +12,7 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ + package io.netty.contrib.handler.codec.redis; import io.netty.buffer.ByteBuf; @@ -21,6 +22,7 @@ * A strategy interface for caching {@link RedisMessage}s. */ @UnstableApi + public interface RedisMessagePool { /** diff --git a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisMessageType.java b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisMessageType.java index 8faf81e..33ca5bd 100644 --- a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisMessageType.java +++ b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/RedisMessageType.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project 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 @@ -12,6 +12,7 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ + package io.netty.contrib.handler.codec.redis; import io.netty.buffer.ByteBuf; diff --git a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/SimpleStringRedisMessage.java b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/SimpleStringRedisMessage.java index dacb351..aaf99ff 100644 --- a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/SimpleStringRedisMessage.java +++ b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/SimpleStringRedisMessage.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project 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 @@ -12,6 +12,7 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ + package io.netty.contrib.handler.codec.redis; import io.netty.util.internal.UnstableApi; @@ -30,4 +31,5 @@ public final class SimpleStringRedisMessage extends AbstractStringRedisMessage { public SimpleStringRedisMessage(String content) { super(content); } + } diff --git a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/package-info.java b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/package-info.java index 43e0f45..679d8d9 100644 --- a/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/package-info.java +++ b/codec-redis/src/main/java/io/netty/contrib/handler/codec/redis/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project 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 diff --git a/examples/pom.xml b/examples/pom.xml index bd71c21..c365bb2 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -7,7 +7,7 @@ io.netty.contrib netty-codec-redis-parent - 5.0.0.Final-SNAPSHOT + 4.1.92.Final-SNAPSHOT netty-codec-redis-examples @@ -20,4 +20,4 @@ ${project.version} - \ No newline at end of file + diff --git a/examples/src/main/java/io/netty/contrib/handler/codec/redis/example/RedisClient.java b/examples/src/main/java/io/netty/contrib/handler/codec/redis/example/RedisClient.java index 6f0d7bc..dff273d 100644 --- a/examples/src/main/java/io/netty/contrib/handler/codec/redis/example/RedisClient.java +++ b/examples/src/main/java/io/netty/contrib/handler/codec/redis/example/RedisClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project 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 @@ -15,23 +15,23 @@ package io.netty.contrib.handler.codec.redis.example; +import java.io.BufferedReader; +import java.io.InputStreamReader; + import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.EventLoopGroup; -import io.netty.channel.MultithreadEventLoopGroup; -import io.netty.channel.nio.NioHandler; +import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.contrib.handler.codec.redis.RedisArrayAggregator; import io.netty.contrib.handler.codec.redis.RedisBulkStringAggregator; import io.netty.contrib.handler.codec.redis.RedisDecoder; import io.netty.contrib.handler.codec.redis.RedisEncoder; -import io.netty.util.concurrent.Future; - -import java.io.BufferedReader; -import java.io.InputStreamReader; +import io.netty.util.concurrent.GenericFutureListener; /** * Simple Redis client that demonstrates Redis commands against a Redis server. @@ -41,7 +41,7 @@ public class RedisClient { private static final int PORT = Integer.parseInt(System.getProperty("port", "6379")); public static void main(String[] args) throws Exception { - EventLoopGroup group = new MultithreadEventLoopGroup(NioHandler.newFactory()); + EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group) @@ -59,11 +59,11 @@ protected void initChannel(SocketChannel ch) throws Exception { }); // Start the connection attempt. - Channel ch = b.connect(HOST, PORT).get(); + Channel ch = b.connect(HOST, PORT).sync().channel(); // Read commands from the stdin. System.out.println("Enter Redis commands (quit to end)"); - Future lastWriteFuture = null; + ChannelFuture lastWriteFuture = null; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); for (;;) { final String input = in.readLine(); @@ -71,16 +71,18 @@ protected void initChannel(SocketChannel ch) throws Exception { if (line == null || "quit".equalsIgnoreCase(line)) { // EOF or "quit" ch.close().sync(); break; - } - if (line.isEmpty()) { // skip `enter` or `enter` with spaces. + } else if (line.isEmpty()) { // skip `enter` or `enter` with spaces. continue; } // Sends the received line to the server. lastWriteFuture = ch.writeAndFlush(line); - lastWriteFuture.addListener(future -> { - if (future.isFailed()) { - System.err.print("write failed: "); - future.cause().printStackTrace(System.err); + lastWriteFuture.addListener(new GenericFutureListener() { + @Override + public void operationComplete(ChannelFuture future) throws Exception { + if (!future.isSuccess()) { + System.err.print("write failed: "); + future.cause().printStackTrace(System.err); + } } }); } diff --git a/examples/src/main/java/io/netty/contrib/handler/codec/redis/example/RedisClientHandler.java b/examples/src/main/java/io/netty/contrib/handler/codec/redis/example/RedisClientHandler.java index 357822b..2b8c414 100644 --- a/examples/src/main/java/io/netty/contrib/handler/codec/redis/example/RedisClientHandler.java +++ b/examples/src/main/java/io/netty/contrib/handler/codec/redis/example/RedisClientHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Netty Project + * Copyright 2016 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance @@ -16,9 +16,13 @@ package io.netty.contrib.handler.codec.redis.example; +import java.util.ArrayList; +import java.util.List; + import io.netty.buffer.ByteBufUtil; -import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPromise; import io.netty.handler.codec.CodecException; import io.netty.contrib.handler.codec.redis.ArrayRedisMessage; import io.netty.contrib.handler.codec.redis.ErrorRedisMessage; @@ -28,25 +32,21 @@ import io.netty.contrib.handler.codec.redis.SimpleStringRedisMessage; import io.netty.util.CharsetUtil; import io.netty.util.ReferenceCountUtil; -import io.netty.util.concurrent.Future; - -import java.util.ArrayList; -import java.util.List; /** * An example Redis client handler. This handler read input from STDIN and write output to STDOUT. */ -public class RedisClientHandler implements ChannelHandler { +public class RedisClientHandler extends ChannelDuplexHandler { @Override - public Future write(ChannelHandlerContext ctx, Object msg) { + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) { String[] commands = ((String) msg).split("\\s+"); - List children = new ArrayList<>(commands.length); + List children = new ArrayList(commands.length); for (String cmdString : commands) { children.add(new FullBulkStringRedisMessage(ByteBufUtil.writeUtf8(ctx.alloc(), cmdString))); } RedisMessage request = new ArrayRedisMessage(children); - return ctx.write(request); + ctx.write(request, promise); } @Override diff --git a/examples/src/main/java/io/netty/contrib/handler/codec/redis/example/RedisServer.java b/examples/src/main/java/io/netty/contrib/handler/codec/redis/example/RedisServer.java new file mode 100644 index 0000000..eaa98b3 --- /dev/null +++ b/examples/src/main/java/io/netty/contrib/handler/codec/redis/example/RedisServer.java @@ -0,0 +1,75 @@ +/* + * Copyright 2023 The Netty Project + * + * The Netty Project 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: + * + * https://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 io.netty.contrib.handler.codec.redis.example; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CountDownLatch; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.contrib.handler.codec.redis.RedisArrayAggregator; +import io.netty.contrib.handler.codec.redis.RedisBulkStringAggregator; +import io.netty.contrib.handler.codec.redis.RedisDecoder; +import io.netty.contrib.handler.codec.redis.RedisEncoder; + +public final class RedisServer { + + private static final int PORT = Integer.parseInt(System.getProperty("port", "6379")); + + public static void main(String[] args) throws Exception { + final EventLoopGroup bossGroup = new NioEventLoopGroup(1); + final EventLoopGroup workerGroup = new NioEventLoopGroup(); + + // This latch will become zero once `RedisServerHandler` receives a SHUTDOWN command. + final CountDownLatch shutdownLatch = new CountDownLatch(1); + final ConcurrentMap map = new ConcurrentHashMap<>(); + + try { + final ServerBootstrap b = new ServerBootstrap(); + b.channel(NioServerSocketChannel.class); + b.group(bossGroup, workerGroup); + b.childHandler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) throws Exception { + final ChannelPipeline p = ch.pipeline(); + p.addLast(new RedisDecoder()); + p.addLast(new RedisBulkStringAggregator()); + p.addLast(new RedisArrayAggregator()); + p.addLast(new RedisEncoder()); + p.addLast(new RedisServerHandler(map, shutdownLatch)); + } + }); + final Channel ch = b.bind(PORT).sync().channel(); + System.err.println("An example Redis server now listening at " + ch.localAddress() + " .."); + + // Wait until the latch becomes zero. + shutdownLatch.await(); + System.err.println("Received a SHUTDOWN command; shutting down .."); + } finally { + bossGroup.shutdownGracefully(); + workerGroup.shutdownGracefully(); + } + } + + private RedisServer() {} +} diff --git a/examples/src/main/java/io/netty/contrib/handler/codec/redis/example/RedisServerHandler.java b/examples/src/main/java/io/netty/contrib/handler/codec/redis/example/RedisServerHandler.java new file mode 100644 index 0000000..fcac8b0 --- /dev/null +++ b/examples/src/main/java/io/netty/contrib/handler/codec/redis/example/RedisServerHandler.java @@ -0,0 +1,212 @@ +/* + * Copyright 2023 The Netty Project + * + * The Netty Project 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: + * + * https://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 io.netty.contrib.handler.codec.redis.example; + +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CountDownLatch; +import java.util.stream.Collectors; + +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.contrib.handler.codec.redis.ArrayRedisMessage; +import io.netty.contrib.handler.codec.redis.ErrorRedisMessage; +import io.netty.contrib.handler.codec.redis.FullBulkStringRedisMessage; +import io.netty.contrib.handler.codec.redis.IntegerRedisMessage; +import io.netty.contrib.handler.codec.redis.RedisMessage; +import io.netty.contrib.handler.codec.redis.SimpleStringRedisMessage; +import io.netty.util.ReferenceCountUtil; + +final class RedisServerHandler extends ChannelInboundHandlerAdapter { + + private final ConcurrentMap map; + private final CountDownLatch shutdownLatch; + + RedisServerHandler(ConcurrentMap map, CountDownLatch shutdownLatch) { + this.map = map; + this.shutdownLatch = shutdownLatch; + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + try { + if (!(msg instanceof ArrayRedisMessage)) { + rejectMalformedRequest(ctx); + return; + } + + final ArrayRedisMessage req = (ArrayRedisMessage) msg; + final List args = req.children(); + for (RedisMessage a : args) { + if (!(a instanceof FullBulkStringRedisMessage)) { + rejectMalformedRequest(ctx); + return; + } + } + + // For simplicity, convert all arguments into strings. + // In a real server, you need to handle them as they are or convert to byte[]. + final List strArgs = + args.stream() + .map(a -> { + final FullBulkStringRedisMessage bulkStr = (FullBulkStringRedisMessage) a; + if (!bulkStr.isNull()) { + return bulkStr.content().toString(StandardCharsets.UTF_8); + } else { + return null; + } + }) + .collect(Collectors.toList()); + + System.err.println(ctx.channel() + " RCVD: " + strArgs); + + final String command = strArgs.get(0); + switch (command) { + case "COMMAND": + ctx.writeAndFlush(ArrayRedisMessage.EMPTY_INSTANCE); + break; + case "GET": { + handleGet(ctx, strArgs); + break; + } + case "SET": { + handleSet(ctx, strArgs); + break; + } + case "DEL": { + handleDel(ctx, strArgs); + break; + } + case "SHUTDOWN": + ctx.writeAndFlush(new SimpleStringRedisMessage("OK")) + .addListener((ChannelFutureListener) f -> { + shutdownLatch.countDown(); + }); + break; + default: + reject(ctx, "ERR Unsupported command"); + } + } finally { + ReferenceCountUtil.release(msg); + } + } + + private void handleGet(ChannelHandlerContext ctx, List strArgs) { + if (strArgs.size() < 2) { + reject(ctx, "ERR A GET command requires a key argument."); + return; + } + + final String key = strArgs.get(1); + if (key == null) { + rejectNilKey(ctx); + return; + } + + final String value = map.get(key); + final FullBulkStringRedisMessage reply; + if (value != null) { + reply = newBulkStringMessage(value); + } else { + reply = FullBulkStringRedisMessage.NULL_INSTANCE; + } + + ctx.writeAndFlush(reply); + } + + private void handleSet(ChannelHandlerContext ctx, List strArgs) { + if (strArgs.size() < 3) { + reject(ctx, "ERR A GET command requires a key argument."); + return; + } + final String key = strArgs.get(1); + final String value = strArgs.get(2); + if (key == null) { + rejectNilKey(ctx); + return; + } + if (value == null) { + reject(ctx, "ERR A nil value is not allowed."); + return; + } + + // Very naive simple detection of 'GET' option. + // Note that we don't support other options which might appear before + // the 'GET' option in reality. + final boolean shouldReplyOldValue = + strArgs.size() > 3 && "GET".equals(strArgs.get(3)); + + final String oldValue = map.put(key, value); + final RedisMessage reply; + if (shouldReplyOldValue) { + if (oldValue != null) { + reply = newBulkStringMessage(oldValue); + } else { + reply = FullBulkStringRedisMessage.NULL_INSTANCE; + } + } else { + reply = new SimpleStringRedisMessage("OK"); + } + + ctx.writeAndFlush(reply); + } + + private void handleDel(ChannelHandlerContext ctx, List strArgs) { + if (strArgs.size() < 2) { + reject(ctx, "ERR A DEL command requires at least one key argument."); + return; + } + int removedEntries = 0; + for (int i = 1; i < strArgs.size(); i++) { + final String key = strArgs.get(i); + if (key == null) { + continue; + } + if (map.remove(key) != null) { + removedEntries++; + } + } + + ctx.writeAndFlush(new IntegerRedisMessage(removedEntries)); + } + + private static FullBulkStringRedisMessage newBulkStringMessage(String oldValue) { + return new FullBulkStringRedisMessage( + Unpooled.copiedBuffer(oldValue, StandardCharsets.UTF_8)); + } + + private static void rejectMalformedRequest(ChannelHandlerContext ctx) { + reject(ctx, "ERR Client request bust be an array of bulk strings."); + } + + private static void rejectNilKey(ChannelHandlerContext ctx) { + reject(ctx, "ERR A nil key is not allowed."); + } + + private static void reject(ChannelHandlerContext ctx, String error) { + ctx.writeAndFlush(new ErrorRedisMessage(error)); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + System.err.println("Unexpected exception handling " + ctx.channel()); + cause.printStackTrace(System.err); + ctx.close(); + } +} diff --git a/pom.xml b/pom.xml index 5735b81..513bc5f 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ io.netty.contrib netty-codec-redis-parent - 5.0.0.Final-SNAPSHOT + 4.1.92.Final-SNAPSHOT Netty/Codec/Redis Parent pom https://netty.io/ @@ -66,7 +66,7 @@ - 5.0.0.Final-SNAPSHOT + 4.1.92.Final-SNAPSHOT 29 github