From 388e4e92e1f5028ff9cbff22f47b03abc9c91aec Mon Sep 17 00:00:00 2001 From: Oleh Dokuka Date: Mon, 27 Apr 2020 23:40:39 +0300 Subject: [PATCH 01/25] fixes readme and bumps versions Signed-off-by: Oleh Dokuka --- README.md | 8 ++++---- gradle.properties | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 538587154..0e055721e 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,8 @@ repositories { mavenCentral() } dependencies { - implementation 'io.rsocket:rsocket-core:1.0.0-RC6' - implementation 'io.rsocket:rsocket-transport-netty:1.0.0-RC6' + implementation 'io.rsocket:rsocket-core:1.0.0-RC7' + implementation 'io.rsocket:rsocket-transport-netty:1.0.0-RC7' } ``` @@ -40,8 +40,8 @@ repositories { maven { url 'https://oss.jfrog.org/oss-snapshot-local' } } dependencies { - implementation 'io.rsocket:rsocket-core:1.0.0-RC7-SNAPSHOT' - implementation 'io.rsocket:rsocket-transport-netty:1.0.0-RC7-SNAPSHOT' + implementation 'io.rsocket:rsocket-core:1.0.0-RC8-SNAPSHOT' + implementation 'io.rsocket:rsocket-transport-netty:1.0.0-RC8-SNAPSHOT' } ``` diff --git a/gradle.properties b/gradle.properties index 3018f4792..2e429e05a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,5 +11,5 @@ # See the License for the specific language governing permissions and # limitations under the License. # -version=1.0.0-RC7 -perfBaselineVersion=1.0.0-RC6 +version=1.0.0-RC8 +perfBaselineVersion=1.0.0-RC7 From 922aa20b2988b50211911037aa8a470dd07a33e3 Mon Sep 17 00:00:00 2001 From: Oleh Dokuka Date: Tue, 28 Apr 2020 09:33:14 +0300 Subject: [PATCH 02/25] fixes compilation issues in perf tests Signed-off-by: Oleh Dokuka --- .../io/rsocket/{ => core}/RSocketPerf.java | 26 ++++++++++--------- .../{ => core}/StreamIdSupplierPerf.java | 12 +++++++-- 2 files changed, 24 insertions(+), 14 deletions(-) rename benchmarks/src/main/java/io/rsocket/{ => core}/RSocketPerf.java (90%) rename benchmarks/src/main/java/io/rsocket/{ => core}/StreamIdSupplierPerf.java (66%) diff --git a/benchmarks/src/main/java/io/rsocket/RSocketPerf.java b/benchmarks/src/main/java/io/rsocket/core/RSocketPerf.java similarity index 90% rename from benchmarks/src/main/java/io/rsocket/RSocketPerf.java rename to benchmarks/src/main/java/io/rsocket/core/RSocketPerf.java index 0c6515140..f78843f5b 100644 --- a/benchmarks/src/main/java/io/rsocket/RSocketPerf.java +++ b/benchmarks/src/main/java/io/rsocket/core/RSocketPerf.java @@ -1,5 +1,11 @@ -package io.rsocket; - +package io.rsocket.core; + +import io.rsocket.AbstractRSocket; +import io.rsocket.Closeable; +import io.rsocket.Payload; +import io.rsocket.PayloadsMaxPerfSubscriber; +import io.rsocket.PayloadsPerfSubscriber; +import io.rsocket.RSocket; import io.rsocket.frame.decoder.PayloadDecoder; import io.rsocket.transport.local.LocalClientTransport; import io.rsocket.transport.local.LocalServerTransport; @@ -59,9 +65,7 @@ public void awaitToBeConsumed() { @Setup public void setUp() throws NoSuchFieldException, IllegalAccessException { server = - RSocketFactory.receive() - .frameDecoder(PayloadDecoder.ZERO_COPY) - .acceptor( + RSocketServer.create( (setup, sendingSocket) -> Mono.just( new AbstractRSocket() { @@ -89,16 +93,14 @@ public Flux requestChannel(Publisher payloads) { return Flux.from(payloads); } })) - .transport(LocalServerTransport.create("server")) - .start() + .payloadDecoder(PayloadDecoder.ZERO_COPY) + .bind(LocalServerTransport.create("server")) .block(); client = - RSocketFactory.connect() - .singleSubscriberRequester() - .frameDecoder(PayloadDecoder.ZERO_COPY) - .transport(LocalClientTransport.create("server")) - .start() + RSocketConnector.create() + .payloadDecoder(PayloadDecoder.ZERO_COPY) + .connect(LocalClientTransport.create("server")) .block(); Field sendProcessorField = RSocketRequester.class.getDeclaredField("sendProcessor"); diff --git a/benchmarks/src/main/java/io/rsocket/StreamIdSupplierPerf.java b/benchmarks/src/main/java/io/rsocket/core/StreamIdSupplierPerf.java similarity index 66% rename from benchmarks/src/main/java/io/rsocket/StreamIdSupplierPerf.java rename to benchmarks/src/main/java/io/rsocket/core/StreamIdSupplierPerf.java index c198b7a19..6b4f3f624 100644 --- a/benchmarks/src/main/java/io/rsocket/StreamIdSupplierPerf.java +++ b/benchmarks/src/main/java/io/rsocket/core/StreamIdSupplierPerf.java @@ -1,8 +1,16 @@ -package io.rsocket; +package io.rsocket.core; import io.netty.util.collection.IntObjectMap; import io.rsocket.internal.SynchronizedIntObjectHashMap; -import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; import org.openjdk.jmh.infra.Blackhole; @BenchmarkMode(Mode.Throughput) From 78082027c8e2590ed4af6db7af780dd44cc45917 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Tue, 28 Apr 2020 07:34:22 +0100 Subject: [PATCH 03/25] Deprecate ResponderRSocket (#802) --- .../main/java/io/rsocket/ResponderRSocket.java | 5 +++++ .../java/io/rsocket/core/RSocketResponder.java | 16 ++++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/rsocket-core/src/main/java/io/rsocket/ResponderRSocket.java b/rsocket-core/src/main/java/io/rsocket/ResponderRSocket.java index f98901472..22697f130 100644 --- a/rsocket-core/src/main/java/io/rsocket/ResponderRSocket.java +++ b/rsocket-core/src/main/java/io/rsocket/ResponderRSocket.java @@ -1,12 +1,17 @@ package io.rsocket; +import java.util.function.BiFunction; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; /** * Extends the {@link RSocket} that allows an implementer to peek at the first request payload of a * channel. + * + * @deprecated as of 1.0 RC7 in favor of using {@link RSocket#requestChannel(Publisher)} with {@link + * Flux#switchOnFirst(BiFunction)} */ +@Deprecated public interface ResponderRSocket extends RSocket { /** * Implement this method to peak at the first payload of the incoming request stream without diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java index b5b298e14..f5c4aecec 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java @@ -27,7 +27,6 @@ import io.rsocket.DuplexConnection; import io.rsocket.Payload; import io.rsocket.RSocket; -import io.rsocket.ResponderRSocket; import io.rsocket.exceptions.ApplicationErrorException; import io.rsocket.frame.*; import io.rsocket.frame.decoder.PayloadDecoder; @@ -51,7 +50,7 @@ import reactor.util.concurrent.Queues; /** Responder side of RSocket. Receives {@link ByteBuf}s from a peer's {@link RSocketRequester} */ -class RSocketResponder implements ResponderRSocket { +class RSocketResponder implements RSocket { private static final Consumer DROPPED_ELEMENTS_CONSUMER = referenceCounted -> { if (referenceCounted.refCnt() > 0) { @@ -66,7 +65,10 @@ class RSocketResponder implements ResponderRSocket { private final DuplexConnection connection; private final RSocket requestHandler; - private final ResponderRSocket responderRSocket; + + @SuppressWarnings("deprecation") + private final io.rsocket.ResponderRSocket responderRSocket; + private final PayloadDecoder payloadDecoder; private final Consumer errorConsumer; private final ResponderLeaseHandler leaseHandler; @@ -86,6 +88,7 @@ class RSocketResponder implements ResponderRSocket { private final UnboundedProcessor sendProcessor; private final ByteBufAllocator allocator; + @SuppressWarnings("deprecation") RSocketResponder( DuplexConnection connection, RSocket requestHandler, @@ -99,7 +102,9 @@ class RSocketResponder implements ResponderRSocket { this.requestHandler = requestHandler; this.responderRSocket = - (requestHandler instanceof ResponderRSocket) ? (ResponderRSocket) requestHandler : null; + (requestHandler instanceof io.rsocket.ResponderRSocket) + ? (io.rsocket.ResponderRSocket) requestHandler + : null; this.payloadDecoder = payloadDecoder; this.errorConsumer = errorConsumer; @@ -219,8 +224,7 @@ public Flux requestChannel(Publisher payloads) { } } - @Override - public Flux requestChannel(Payload payload, Publisher payloads) { + private Flux requestChannel(Payload payload, Publisher payloads) { try { if (leaseHandler.useLease()) { return responderRSocket.requestChannel(payload, payloads); From 444709a131fc1e98a9c694e6cba20ad11b016cb7 Mon Sep 17 00:00:00 2001 From: Oleh Dokuka Date: Tue, 28 Apr 2020 09:43:34 +0300 Subject: [PATCH 04/25] fixes code sample --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 0e055721e..8a2ba991c 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,6 @@ RSocket clientRSocket = // Enable Zero Copy .payloadDecoder(PayloadDecoder.ZERO_COPY) .connect(TcpClientTransport.create(7878)) - .start() .block(); ``` From 86ac4a0669f3aa70e9a107a454f06024b129bde4 Mon Sep 17 00:00:00 2001 From: Oleh Dokuka Date: Tue, 28 Apr 2020 15:54:32 +0300 Subject: [PATCH 05/25] Removes TupleByteBufs (#804) --- .../rsocket/buffer/AbstractTupleByteBuf.java | 607 ------------------ .../java/io/rsocket/buffer/BufferUtil.java | 78 --- .../java/io/rsocket/buffer/Tuple2ByteBuf.java | 394 ------------ .../java/io/rsocket/buffer/Tuple3ByteBuf.java | 571 ---------------- .../java/io/rsocket/buffer/TupleByteBuf.java | 35 - .../io/rsocket/buffer/Tuple3ByteBufTest.java | 98 --- 6 files changed, 1783 deletions(-) delete mode 100644 rsocket-core/src/main/java/io/rsocket/buffer/AbstractTupleByteBuf.java delete mode 100644 rsocket-core/src/main/java/io/rsocket/buffer/BufferUtil.java delete mode 100644 rsocket-core/src/main/java/io/rsocket/buffer/Tuple2ByteBuf.java delete mode 100644 rsocket-core/src/main/java/io/rsocket/buffer/Tuple3ByteBuf.java delete mode 100644 rsocket-core/src/main/java/io/rsocket/buffer/TupleByteBuf.java delete mode 100644 rsocket-core/src/test/java/io/rsocket/buffer/Tuple3ByteBufTest.java diff --git a/rsocket-core/src/main/java/io/rsocket/buffer/AbstractTupleByteBuf.java b/rsocket-core/src/main/java/io/rsocket/buffer/AbstractTupleByteBuf.java deleted file mode 100644 index a80605877..000000000 --- a/rsocket-core/src/main/java/io/rsocket/buffer/AbstractTupleByteBuf.java +++ /dev/null @@ -1,607 +0,0 @@ -package io.rsocket.buffer; - -import io.netty.buffer.AbstractReferenceCountedByteBuf; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.Unpooled; -import io.netty.util.internal.SystemPropertyUtil; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.channels.FileChannel; -import java.nio.channels.ScatteringByteChannel; -import java.nio.charset.Charset; - -abstract class AbstractTupleByteBuf extends AbstractReferenceCountedByteBuf { - static final int DEFAULT_DIRECT_MEMORY_CACHE_ALIGNMENT = - SystemPropertyUtil.getInt("io.netty.allocator.directMemoryCacheAlignment", 0); - static final ByteBuffer EMPTY_NIO_BUFFER = Unpooled.EMPTY_BUFFER.nioBuffer(); - static final int NOT_ENOUGH_BYTES_AT_MAX_CAPACITY_CODE = 3; - - final ByteBufAllocator allocator; - final int capacity; - - AbstractTupleByteBuf(ByteBufAllocator allocator, int capacity) { - super(Integer.MAX_VALUE); - - this.capacity = capacity; - this.allocator = allocator; - super.writerIndex(capacity); - } - - abstract long calculateRelativeIndex(int index); - - abstract ByteBuf getPart(int index); - - @Override - public ByteBuffer nioBuffer(int index, int length) { - checkIndex(index, length); - - ByteBuffer[] buffers = nioBuffers(index, length); - - if (buffers.length == 1) { - return buffers[0].duplicate(); - } - - ByteBuffer merged = - BufferUtil.allocateDirectAligned(length, DEFAULT_DIRECT_MEMORY_CACHE_ALIGNMENT) - .order(order()); - for (ByteBuffer buf : buffers) { - merged.put(buf); - } - - merged.flip(); - return merged; - } - - @Override - public ByteBuffer[] nioBuffers(int index, int length) { - checkIndex(index, length); - if (length == 0) { - return new ByteBuffer[] {EMPTY_NIO_BUFFER}; - } - return _nioBuffers(index, length); - } - - protected abstract ByteBuffer[] _nioBuffers(int index, int length); - - @Override - protected byte _getByte(final int index) { - long ri = calculateRelativeIndex(index); - ByteBuf byteBuf = getPart(index); - - int calculatedIndex = (int) (ri & Integer.MAX_VALUE); - - return byteBuf.getByte(calculatedIndex); - } - - @Override - protected short _getShort(final int index) { - long ri = calculateRelativeIndex(index); - ByteBuf byteBuf = getPart(index); - - final int calculatedIndex = (int) (ri & Integer.MAX_VALUE); - - if (calculatedIndex + Short.BYTES <= byteBuf.writerIndex()) { - return byteBuf.getShort(calculatedIndex); - } else if (order() == ByteOrder.BIG_ENDIAN) { - return (short) ((_getByte(index) & 0xff) << 8 | _getByte(index + 1) & 0xff); - } else { - return (short) (_getByte(index) & 0xff | (_getByte(index + 1) & 0xff) << 8); - } - } - - @Override - protected short _getShortLE(int index) { - long ri = calculateRelativeIndex(index); - ByteBuf byteBuf = getPart(index); - - final int calculatedIndex = (int) (ri & Integer.MAX_VALUE); - - if (calculatedIndex + Short.BYTES <= byteBuf.writerIndex()) { - return byteBuf.getShortLE(calculatedIndex); - } else if (order() == ByteOrder.BIG_ENDIAN) { - return (short) (_getByte(index) & 0xff | (_getByte(index + 1) & 0xff) << 8); - } else { - return (short) ((_getByte(index) & 0xff) << 8 | _getByte(index + 1) & 0xff); - } - } - - @Override - protected int _getUnsignedMedium(final int index) { - long ri = calculateRelativeIndex(index); - ByteBuf byteBuf = getPart(index); - - int calculatedIndex = (int) (ri & Integer.MAX_VALUE); - - if (calculatedIndex + 3 <= byteBuf.writerIndex()) { - return byteBuf.getUnsignedMedium(calculatedIndex); - } else if (order() == ByteOrder.BIG_ENDIAN) { - return (_getShort(index) & 0xffff) << 8 | _getByte(index + 2) & 0xff; - } else { - return _getShort(index) & 0xFFFF | (_getByte(index + 2) & 0xFF) << 16; - } - } - - @Override - protected int _getUnsignedMediumLE(int index) { - long ri = calculateRelativeIndex(index); - ByteBuf byteBuf = getPart(index); - - int calculatedIndex = (int) (ri & Integer.MAX_VALUE); - - if (calculatedIndex + 3 <= byteBuf.writerIndex()) { - return byteBuf.getUnsignedMediumLE(calculatedIndex); - } else if (order() == ByteOrder.BIG_ENDIAN) { - return _getShortLE(index) & 0xffff | (_getByte(index + 2) & 0xff) << 16; - } else { - return (_getShortLE(index) & 0xffff) << 8 | _getByte(index + 2) & 0xff; - } - } - - @Override - protected int _getInt(final int index) { - long ri = calculateRelativeIndex(index); - ByteBuf byteBuf = getPart(index); - - int calculatedIndex = (int) (ri & Integer.MAX_VALUE); - - if (calculatedIndex + Integer.BYTES <= byteBuf.writerIndex()) { - return byteBuf.getInt(calculatedIndex); - } else if (order() == ByteOrder.BIG_ENDIAN) { - return (_getShort(index) & 0xffff) << 16 | _getShort(index + 2) & 0xffff; - } else { - return _getShort(index) & 0xFFFF | (_getShort(index + 2) & 0xFFFF) << 16; - } - } - - @Override - protected int _getIntLE(final int index) { - long ri = calculateRelativeIndex(index); - ByteBuf byteBuf = getPart(index); - - int calculatedIndex = (int) (ri & Integer.MAX_VALUE); - - if (calculatedIndex + Integer.BYTES <= byteBuf.writerIndex()) { - return byteBuf.getIntLE(calculatedIndex); - } else if (order() == ByteOrder.BIG_ENDIAN) { - return _getShortLE(index) & 0xffff | (_getShortLE(index + 2) & 0xffff) << 16; - } else { - return (_getShortLE(index) & 0xffff) << 16 | _getShortLE(index + 2) & 0xffff; - } - } - - @Override - protected long _getLong(final int index) { - long ri = calculateRelativeIndex(index); - ByteBuf byteBuf = getPart(index); - - int calculatedIndex = (int) (ri & Integer.MAX_VALUE); - - if (calculatedIndex + Long.BYTES <= byteBuf.writerIndex()) { - return byteBuf.getLong(calculatedIndex); - } else if (order() == ByteOrder.BIG_ENDIAN) { - return (_getInt(index) & 0xffffffffL) << 32 | _getInt(index + 4) & 0xffffffffL; - } else { - return _getInt(index) & 0xFFFFFFFFL | (_getInt(index + 4) & 0xFFFFFFFFL) << 32; - } - } - - @Override - protected long _getLongLE(final int index) { - long ri = calculateRelativeIndex(index); - ByteBuf byteBuf = getPart(index); - - int calculatedIndex = (int) (ri & Integer.MAX_VALUE); - - if (calculatedIndex + Long.BYTES <= byteBuf.writerIndex()) { - return byteBuf.getLongLE(calculatedIndex); - } else if (order() == ByteOrder.BIG_ENDIAN) { - return (_getInt(index) & 0xffffffffL) << 32 | _getInt(index + 4) & 0xffffffffL; - } else { - return _getInt(index) & 0xFFFFFFFFL | (_getInt(index + 4) & 0xFFFFFFFFL) << 32; - } - } - - @Override - public ByteBufAllocator alloc() { - return allocator; - } - - @Override - public int capacity() { - return capacity; - } - - @Override - public ByteBuf capacity(int newCapacity) { - throw new UnsupportedOperationException(); - } - - @Override - public int maxCapacity() { - return capacity; - } - - @Override - public ByteOrder order() { - return ByteOrder.LITTLE_ENDIAN; - } - - @Override - public ByteBuf order(ByteOrder endianness) { - return this; - } - - @Override - public ByteBuf unwrap() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isReadOnly() { - return true; - } - - @Override - public ByteBuf asReadOnly() { - return this; - } - - @Override - public boolean isWritable() { - return false; - } - - @Override - public boolean isWritable(int size) { - return false; - } - - @Override - public ByteBuf writerIndex(int writerIndex) { - return this; - } - - @Override - public final int writerIndex() { - return capacity; - } - - @Override - public ByteBuf setIndex(int readerIndex, int writerIndex) { - return this; - } - - @Override - public ByteBuf clear() { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf discardReadBytes() { - return this; - } - - @Override - public ByteBuf discardSomeReadBytes() { - return this; - } - - @Override - public ByteBuf ensureWritable(int minWritableBytes) { - return this; - } - - @Override - public int ensureWritable(int minWritableBytes, boolean force) { - return NOT_ENOUGH_BYTES_AT_MAX_CAPACITY_CODE; - } - - @Override - public ByteBuf setFloatLE(int index, float value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf setDoubleLE(int index, double value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf setBoolean(int index, boolean value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf setByte(int index, int value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf setShort(int index, int value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf setShortLE(int index, int value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf setMedium(int index, int value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf setMediumLE(int index, int value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf setInt(int index, int value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf setIntLE(int index, int value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf setLong(int index, long value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf setLongLE(int index, long value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf setChar(int index, int value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf setFloat(int index, float value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf setDouble(int index, double value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf setBytes(int index, ByteBuf src) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf setBytes(int index, ByteBuf src, int length) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf setBytes(int index, byte[] src) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf setBytes(int index, ByteBuffer src) { - throw new UnsupportedOperationException(); - } - - @Override - public int setBytes(int index, InputStream in, int length) { - throw new UnsupportedOperationException(); - } - - @Override - public int setBytes(int index, ScatteringByteChannel in, int length) { - throw new UnsupportedOperationException(); - } - - @Override - public int setBytes(int index, FileChannel in, long position, int length) { - throw new UnsupportedOperationException(); - } - - @Override - public int setCharSequence(int index, CharSequence sequence, Charset charset) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf setZero(int index, int length) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf writeBoolean(boolean value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf writeByte(int value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf writeShort(int value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf writeShortLE(int value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf writeMedium(int value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf writeMediumLE(int value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf writeInt(int value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf writeIntLE(int value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf writeLong(long value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf writeLongLE(long value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf writeChar(int value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf writeFloat(float value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf writeDouble(double value) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf writeBytes(ByteBuf src) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf writeBytes(ByteBuf src, int length) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf writeBytes(ByteBuf src, int srcIndex, int length) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf writeBytes(byte[] src) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf writeBytes(byte[] src, int srcIndex, int length) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf writeBytes(ByteBuffer src) { - throw new UnsupportedOperationException(); - } - - @Override - public int writeBytes(InputStream in, int length) { - throw new UnsupportedOperationException(); - } - - @Override - public int writeBytes(ScatteringByteChannel in, int length) { - throw new UnsupportedOperationException(); - } - - @Override - public int writeBytes(FileChannel in, long position, int length) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuf writeZero(int length) { - throw new UnsupportedOperationException(); - } - - @Override - public int writeCharSequence(CharSequence sequence, Charset charset) { - throw new UnsupportedOperationException(); - } - - @Override - public ByteBuffer internalNioBuffer(int index, int length) { - return nioBuffer(index, length); - } - - @Override - public boolean hasArray() { - return false; - } - - @Override - public byte[] array() { - throw new UnsupportedOperationException(); - } - - @Override - public int arrayOffset() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean hasMemoryAddress() { - return false; - } - - @Override - public long memoryAddress() { - throw new UnsupportedOperationException(); - } - - @Override - protected void _setByte(int index, int value) {} - - @Override - protected void _setShort(int index, int value) {} - - @Override - protected void _setShortLE(int index, int value) {} - - @Override - protected void _setMedium(int index, int value) {} - - @Override - protected void _setMediumLE(int index, int value) {} - - @Override - protected void _setInt(int index, int value) {} - - @Override - protected void _setIntLE(int index, int value) {} - - @Override - protected void _setLong(int index, long value) {} - - @Override - protected void _setLongLE(int index, long value) {} -} diff --git a/rsocket-core/src/main/java/io/rsocket/buffer/BufferUtil.java b/rsocket-core/src/main/java/io/rsocket/buffer/BufferUtil.java deleted file mode 100644 index 476583ab3..000000000 --- a/rsocket-core/src/main/java/io/rsocket/buffer/BufferUtil.java +++ /dev/null @@ -1,78 +0,0 @@ -package io.rsocket.buffer; - -import java.lang.reflect.Field; -import java.nio.Buffer; -import java.nio.ByteBuffer; -import java.security.AccessController; -import java.security.PrivilegedExceptionAction; -import sun.misc.Unsafe; - -abstract class BufferUtil { - - private static final Unsafe UNSAFE; - - static { - Unsafe unsafe; - try { - final PrivilegedExceptionAction action = - () -> { - final Field f = Unsafe.class.getDeclaredField("theUnsafe"); - f.setAccessible(true); - - return (Unsafe) f.get(null); - }; - - unsafe = AccessController.doPrivileged(action); - } catch (final Exception ex) { - throw new RuntimeException(ex); - } - - UNSAFE = unsafe; - } - - private static final long BYTE_BUFFER_ADDRESS_FIELD_OFFSET; - - static { - try { - BYTE_BUFFER_ADDRESS_FIELD_OFFSET = - UNSAFE.objectFieldOffset(Buffer.class.getDeclaredField("address")); - } catch (final Exception ex) { - throw new RuntimeException(ex); - } - } - - /** - * Allocate a new direct {@link ByteBuffer} that is aligned on a given alignment boundary. - * - * @param capacity required for the buffer. - * @param alignment boundary at which the buffer should begin. - * @return a new {@link ByteBuffer} with the required alignment. - * @throws IllegalArgumentException if the alignment is not a power of 2. - */ - static ByteBuffer allocateDirectAligned(final int capacity, final int alignment) { - if (alignment == 0) { - return ByteBuffer.allocateDirect(capacity); - } - - if (!isPowerOfTwo(alignment)) { - throw new IllegalArgumentException("Must be a power of 2: alignment=" + alignment); - } - - final ByteBuffer buffer = ByteBuffer.allocateDirect(capacity + alignment); - - final long address = UNSAFE.getLong(buffer, BYTE_BUFFER_ADDRESS_FIELD_OFFSET); - final int remainder = (int) (address & (alignment - 1)); - final int offset = alignment - remainder; - - buffer.limit(capacity + offset); - buffer.position(offset); - - return buffer.slice(); - } - - private static boolean isPowerOfTwo(final int value) { - return value > 0 && ((value & (~value + 1)) == value); - } - - private BufferUtil() {} -} diff --git a/rsocket-core/src/main/java/io/rsocket/buffer/Tuple2ByteBuf.java b/rsocket-core/src/main/java/io/rsocket/buffer/Tuple2ByteBuf.java deleted file mode 100644 index ba6620cb0..000000000 --- a/rsocket-core/src/main/java/io/rsocket/buffer/Tuple2ByteBuf.java +++ /dev/null @@ -1,394 +0,0 @@ -package io.rsocket.buffer; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.Unpooled; -import io.netty.util.ReferenceCountUtil; -import java.io.IOException; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.nio.channels.GatheringByteChannel; -import java.nio.charset.Charset; - -class Tuple2ByteBuf extends AbstractTupleByteBuf { - - private static final long ONE_MASK = 0x100000000L; - private static final long TWO_MASK = 0x200000000L; - private static final long MASK = 0x700000000L; - - private final ByteBuf one; - private final ByteBuf two; - private final int oneReadIndex; - private final int twoReadIndex; - private final int oneReadableBytes; - private final int twoReadableBytes; - private final int twoRelativeIndex; - - private boolean freed; - - Tuple2ByteBuf(ByteBufAllocator allocator, ByteBuf one, ByteBuf two) { - super(allocator, one.readableBytes() + two.readableBytes()); - - this.one = one; - this.two = two; - - this.oneReadIndex = one.readerIndex(); - this.twoReadIndex = two.readerIndex(); - - this.oneReadableBytes = one.readableBytes(); - this.twoReadableBytes = two.readableBytes(); - - this.twoRelativeIndex = oneReadableBytes; - - this.freed = false; - } - - @Override - long calculateRelativeIndex(int index) { - checkIndex(index, 0); - - long relativeIndex; - long mask; - if (index >= twoRelativeIndex) { - relativeIndex = twoReadIndex + (index - oneReadableBytes); - mask = TWO_MASK; - } else { - relativeIndex = oneReadIndex + index; - mask = ONE_MASK; - } - - return relativeIndex | mask; - } - - @Override - ByteBuf getPart(int index) { - long ri = calculateRelativeIndex(index); - switch ((int) ((ri & MASK) >>> 32L)) { - case 0x1: - return one; - case 0x2: - return two; - default: - throw new IllegalStateException(); - } - } - - @Override - public boolean isDirect() { - return one.isDirect() && two.isDirect(); - } - - @Override - public int nioBufferCount() { - return one.nioBufferCount() + two.nioBufferCount(); - } - - @Override - public ByteBuffer nioBuffer() { - ByteBuffer[] oneBuffers = one.nioBuffers(); - ByteBuffer[] twoBuffers = two.nioBuffers(); - - ByteBuffer merged = - BufferUtil.allocateDirectAligned(capacity, DEFAULT_DIRECT_MEMORY_CACHE_ALIGNMENT) - .order(order()); - - for (ByteBuffer b : oneBuffers) { - merged.put(b); - } - - for (ByteBuffer b : twoBuffers) { - merged.put(b); - } - - merged.flip(); - return merged; - } - - @Override - public ByteBuffer[] _nioBuffers(int index, int length) { - long ri = calculateRelativeIndex(index); - index = (int) (ri & Integer.MAX_VALUE); - switch ((int) ((ri & MASK) >>> 32L)) { - case 0x1: - ByteBuffer[] oneBuffer; - ByteBuffer[] twoBuffer; - int l = Math.min(oneReadableBytes - index, length); - oneBuffer = one.nioBuffers(index, l); - length -= l; - if (length != 0) { - twoBuffer = two.nioBuffers(twoReadIndex, length); - ByteBuffer[] results = new ByteBuffer[oneBuffer.length + twoBuffer.length]; - System.arraycopy(oneBuffer, 0, results, 0, oneBuffer.length); - System.arraycopy(twoBuffer, 0, results, oneBuffer.length, twoBuffer.length); - return results; - } else { - return oneBuffer; - } - case 0x2: - return two.nioBuffers(index, length); - default: - throw new IllegalStateException(); - } - } - - @Override - public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) { - checkDstIndex(index, length, dstIndex, dst.capacity()); - if (length == 0) { - return this; - } - - // FIXME: check twice here - long ri = calculateRelativeIndex(index); - index = (int) (ri & Integer.MAX_VALUE); - switch ((int) ((ri & MASK) >>> 32L)) { - case 0x1: - { - int l = Math.min(oneReadableBytes - index, length); - one.getBytes(index, dst, dstIndex, l); - length -= l; - dstIndex += l; - - if (length != 0) { - two.getBytes(twoReadIndex, dst, dstIndex, length); - } - - break; - } - case 0x2: - { - two.getBytes(index, dst, dstIndex, length); - break; - } - default: - throw new IllegalStateException(); - } - - return this; - } - - @Override - public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) { - ByteBuf dstBuf = Unpooled.wrappedBuffer(dst); - return getBytes(index, dstBuf, dstIndex, length); - } - - @Override - public ByteBuf getBytes(int index, ByteBuffer dst) { - ByteBuf dstBuf = Unpooled.wrappedBuffer(dst); - return getBytes(index, dstBuf); - } - - @Override - public ByteBuf getBytes(int index, final OutputStream out, int length) throws IOException { - checkIndex(index, length); - if (length == 0) { - return this; - } - - long ri = calculateRelativeIndex(index); - index = (int) (ri & Integer.MAX_VALUE); - switch ((int) ((ri & MASK) >>> 32L)) { - case 0x1: - { - int l = Math.min(oneReadableBytes - index, length); - one.getBytes(index, out, l); - length -= l; - if (length != 0) { - two.getBytes(twoReadIndex, out, length); - } - break; - } - case 0x2: - { - two.getBytes(index, out, length); - break; - } - default: - throw new IllegalStateException(); - } - - return this; - } - - @Override - public int getBytes(int index, GatheringByteChannel out, int length) throws IOException { - checkIndex(index, length); - int read = 0; - long ri = calculateRelativeIndex(index); - index = (int) (ri & Integer.MAX_VALUE); - switch ((int) ((ri & MASK) >>> 32L)) { - case 0x1: - { - int l = Math.min(oneReadableBytes - index, length); - read += one.getBytes(index, out, l); - length -= l; - if (length != 0) { - read += two.getBytes(twoReadIndex, out, length); - } - break; - } - case 0x2: - { - read += two.getBytes(index, out, length); - break; - } - default: - throw new IllegalStateException(); - } - - return read; - } - - @Override - public int getBytes(int index, FileChannel out, long position, int length) throws IOException { - checkIndex(index, length); - int read = 0; - long ri = calculateRelativeIndex(index); - index = (int) (ri & Integer.MAX_VALUE); - switch ((int) ((ri & MASK) >>> 32L)) { - case 0x1: - { - int l = Math.min(oneReadableBytes - index, length); - read += one.getBytes(index, out, position, l); - length -= l; - position += l; - if (length != 0) { - read += two.getBytes(twoReadIndex, out, position, length); - } - break; - } - case 0x2: - { - read += two.getBytes(index, out, position, length); - break; - } - default: - throw new IllegalStateException(); - } - - return read; - } - - @Override - public ByteBuf copy(int index, int length) { - checkIndex(index, length); - - ByteBuf buffer = allocator.buffer(length); - - if (index == 0 && length == capacity) { - buffer.writeBytes(one, oneReadIndex, oneReadableBytes); - buffer.writeBytes(two, twoReadIndex, twoReadableBytes); - - return buffer; - } - - long ri = calculateRelativeIndex(index); - index = (int) (ri & Integer.MAX_VALUE); - - switch ((int) ((ri & MASK) >>> 32L)) { - case 0x1: - { - int l = Math.min(oneReadableBytes - index, length); - buffer.writeBytes(one, index, l); - - length -= l; - - if (length != 0) { - buffer.writeBytes(two, twoReadIndex, length); - } - - return buffer; - } - case 0x2: - { - return buffer.writeBytes(two, index, length); - } - default: - throw new IllegalStateException(); - } - } - - @Override - public ByteBuf slice(final int readIndex, int length) { - checkIndex(readIndex, length); - - if (readIndex == 0 && length == capacity) { - return new Tuple2ByteBuf( - allocator, - one.slice(oneReadIndex, oneReadableBytes), - two.slice(twoReadIndex, twoReadableBytes)); - } - - long ri = calculateRelativeIndex(readIndex); - int index = (int) (ri & Integer.MAX_VALUE); - - switch ((int) ((ri & MASK) >>> 32L)) { - case 0x1: - { - ByteBuf oneSlice; - ByteBuf twoSlice; - - int l = Math.min(oneReadableBytes - index, length); - oneSlice = one.slice(index, l); - length -= l; - if (length != 0) { - twoSlice = two.slice(twoReadIndex, length); - return new Tuple2ByteBuf(allocator, oneSlice, twoSlice); - } else { - return oneSlice; - } - } - case 0x2: - { - return two.slice(index, length); - } - default: - throw new IllegalStateException(); - } - } - - @Override - protected void deallocate() { - if (freed) { - return; - } - - freed = true; - ReferenceCountUtil.safeRelease(one); - ReferenceCountUtil.safeRelease(two); - } - - @Override - public String toString(Charset charset) { - StringBuilder builder = new StringBuilder(capacity); - builder.append(one.toString(charset)); - builder.append(two.toString(charset)); - return builder.toString(); - } - - @Override - public String toString() { - return "Tuple2ByteBuf{" - + "capacity=" - + capacity - + ", one=" - + one - + ", two=" - + two - + ", allocator=" - + allocator - + ", oneReadIndex=" - + oneReadIndex - + ", twoReadIndex=" - + twoReadIndex - + ", oneReadableBytes=" - + oneReadableBytes - + ", twoReadableBytes=" - + twoReadableBytes - + ", twoRelativeIndex=" - + twoRelativeIndex - + '}'; - } -} diff --git a/rsocket-core/src/main/java/io/rsocket/buffer/Tuple3ByteBuf.java b/rsocket-core/src/main/java/io/rsocket/buffer/Tuple3ByteBuf.java deleted file mode 100644 index be593019f..000000000 --- a/rsocket-core/src/main/java/io/rsocket/buffer/Tuple3ByteBuf.java +++ /dev/null @@ -1,571 +0,0 @@ -package io.rsocket.buffer; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.Unpooled; -import io.netty.util.ReferenceCountUtil; -import java.io.IOException; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.nio.channels.GatheringByteChannel; -import java.nio.charset.Charset; - -class Tuple3ByteBuf extends AbstractTupleByteBuf { - private static final long ONE_MASK = 0x100000000L; - private static final long TWO_MASK = 0x200000000L; - private static final long THREE_MASK = 0x400000000L; - private static final long MASK = 0x700000000L; - - private final ByteBuf one; - private final ByteBuf two; - private final ByteBuf three; - private final int oneReadIndex; - private final int twoReadIndex; - private final int threeReadIndex; - private final int oneReadableBytes; - private final int twoReadableBytes; - private final int threeReadableBytes; - private final int twoRelativeIndex; - private final int threeRelativeIndex; - - private boolean freed; - - Tuple3ByteBuf(ByteBufAllocator allocator, ByteBuf one, ByteBuf two, ByteBuf three) { - super(allocator, one.readableBytes() + two.readableBytes() + three.readableBytes()); - - this.one = one; - this.two = two; - this.three = three; - - this.oneReadIndex = one.readerIndex(); - this.twoReadIndex = two.readerIndex(); - this.threeReadIndex = three.readerIndex(); - - this.oneReadableBytes = one.readableBytes(); - this.twoReadableBytes = two.readableBytes(); - this.threeReadableBytes = three.readableBytes(); - - this.twoRelativeIndex = oneReadableBytes; - this.threeRelativeIndex = twoRelativeIndex + twoReadableBytes; - - this.freed = false; - } - - @Override - public boolean isDirect() { - return one.isDirect() && two.isDirect() && three.isDirect(); - } - - @Override - public long calculateRelativeIndex(int index) { - checkIndex(index, 0); - long relativeIndex; - long mask; - if (index >= threeRelativeIndex) { - relativeIndex = threeReadIndex + (index - twoReadableBytes - oneReadableBytes); - mask = THREE_MASK; - } else if (index >= twoRelativeIndex) { - relativeIndex = twoReadIndex + (index - oneReadableBytes); - mask = TWO_MASK; - } else { - relativeIndex = oneReadIndex + index; - mask = ONE_MASK; - } - - return relativeIndex | mask; - } - - @Override - public ByteBuf getPart(int index) { - long ri = calculateRelativeIndex(index); - switch ((int) ((ri & MASK) >>> 32L)) { - case 0x1: - return one; - case 0x2: - return two; - case 0x4: - return three; - default: - throw new IllegalStateException(); - } - } - - @Override - public int nioBufferCount() { - return one.nioBufferCount() + two.nioBufferCount() + three.nioBufferCount(); - } - - @Override - public ByteBuffer nioBuffer() { - - ByteBuffer[] oneBuffers = one.nioBuffers(); - ByteBuffer[] twoBuffers = two.nioBuffers(); - ByteBuffer[] threeBuffers = three.nioBuffers(); - - ByteBuffer merged = - BufferUtil.allocateDirectAligned(capacity, DEFAULT_DIRECT_MEMORY_CACHE_ALIGNMENT) - .order(order()); - - for (ByteBuffer b : oneBuffers) { - merged.put(b); - } - - for (ByteBuffer b : twoBuffers) { - merged.put(b); - } - - for (ByteBuffer b : threeBuffers) { - merged.put(b); - } - - merged.flip(); - return merged; - } - - @Override - public ByteBuffer[] _nioBuffers(int index, int length) { - long ri = calculateRelativeIndex(index); - index = (int) (ri & Integer.MAX_VALUE); - switch ((int) ((ri & MASK) >>> 32L)) { - case 0x1: - { - ByteBuffer[] oneBuffer; - ByteBuffer[] twoBuffer; - ByteBuffer[] threeBuffer; - int l = Math.min(oneReadableBytes - index, length); - oneBuffer = one.nioBuffers(index, l); - length -= l; - if (length != 0) { - l = Math.min(twoReadableBytes, length); - twoBuffer = two.nioBuffers(twoReadIndex, l); - length -= l; - if (length != 0) { - threeBuffer = three.nioBuffers(threeReadIndex, length); - ByteBuffer[] results = - new ByteBuffer[oneBuffer.length + twoBuffer.length + threeBuffer.length]; - System.arraycopy(oneBuffer, 0, results, 0, oneBuffer.length); - System.arraycopy(twoBuffer, 0, results, oneBuffer.length, twoBuffer.length); - System.arraycopy( - threeBuffer, 0, results, oneBuffer.length + twoBuffer.length, threeBuffer.length); - return results; - } else { - ByteBuffer[] results = new ByteBuffer[oneBuffer.length + twoBuffer.length]; - System.arraycopy(oneBuffer, 0, results, 0, oneBuffer.length); - System.arraycopy(twoBuffer, 0, results, oneBuffer.length, twoBuffer.length); - return results; - } - } else { - return oneBuffer; - } - } - case 0x2: - { - ByteBuffer[] twoBuffer; - ByteBuffer[] threeBuffer; - int l = Math.min(twoReadableBytes - index, length); - twoBuffer = two.nioBuffers(index, l); - length -= l; - if (length != 0) { - threeBuffer = three.nioBuffers(threeReadIndex, length); - ByteBuffer[] results = new ByteBuffer[twoBuffer.length + threeBuffer.length]; - System.arraycopy(twoBuffer, 0, results, 0, twoBuffer.length); - System.arraycopy(threeBuffer, 0, results, twoBuffer.length, threeBuffer.length); - return results; - } else { - return twoBuffer; - } - } - case 0x4: - return three.nioBuffers(index, length); - default: - throw new IllegalStateException(); - } - } - - @Override - public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) { - checkDstIndex(index, length, dstIndex, dst.capacity()); - long ri = calculateRelativeIndex(index); - index = (int) (ri & Integer.MAX_VALUE); - switch ((int) ((ri & MASK) >>> 32L)) { - case 0x1: - { - int l = Math.min(oneReadableBytes - index, length); - one.getBytes(index, dst, dstIndex, l); - length -= l; - dstIndex += l; - - if (length != 0) { - l = Math.min(twoReadableBytes, length); - two.getBytes(twoReadIndex, dst, dstIndex, l); - length -= l; - dstIndex += l; - - if (length != 0) { - three.getBytes(threeReadIndex, dst, dstIndex, length); - } - } - break; - } - case 0x2: - { - int l = Math.min(twoReadableBytes - index, length); - two.getBytes(index, dst, dstIndex, l); - length -= l; - dstIndex += l; - - if (length != 0) { - three.getBytes(threeReadIndex, dst, dstIndex, length); - } - break; - } - case 0x4: - { - three.getBytes(index, dst, dstIndex, length); - break; - } - default: - throw new IllegalStateException(); - } - - return this; - } - - @Override - public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) { - ByteBuf dstBuf = Unpooled.wrappedBuffer(dst); - return getBytes(index, dstBuf, dstIndex, length); - } - - @Override - public ByteBuf getBytes(int index, ByteBuffer dst) { - ByteBuf dstBuf = Unpooled.wrappedBuffer(dst); - return getBytes(index, dstBuf); - } - - @Override - public ByteBuf getBytes(int index, final OutputStream out, int length) throws IOException { - checkIndex(index, length); - long ri = calculateRelativeIndex(index); - index = (int) (ri & Integer.MAX_VALUE); - switch ((int) ((ri & MASK) >>> 32L)) { - case 0x1: - { - int l = Math.min(oneReadableBytes - index, length); - one.getBytes(index, out, l); - length -= l; - if (length != 0) { - l = Math.min(twoReadableBytes, length); - two.getBytes(twoReadIndex, out, l); - length -= l; - if (length != 0) { - three.getBytes(threeReadIndex, out, length); - } - } - break; - } - case 0x2: - { - int l = Math.min(twoReadableBytes - index, length); - two.getBytes(index, out, l); - length -= l; - - if (length != 0) { - three.getBytes(threeReadIndex, out, length); - } - break; - } - case 0x4: - { - three.getBytes(index, out, length); - - break; - } - default: - throw new IllegalStateException(); - } - - return this; - } - - @Override - public int getBytes(int index, GatheringByteChannel out, int length) throws IOException { - checkIndex(index, length); - int read = 0; - long ri = calculateRelativeIndex(index); - index = (int) (ri & Integer.MAX_VALUE); - switch ((int) ((ri & MASK) >>> 32L)) { - case 0x1: - { - int l = Math.min(oneReadableBytes - index, length); - read += one.getBytes(index, out, l); - length -= l; - if (length != 0) { - l = Math.min(twoReadableBytes, length); - read += two.getBytes(twoReadIndex, out, l); - length -= l; - if (length != 0) { - read += three.getBytes(threeReadIndex, out, length); - } - } - break; - } - case 0x2: - { - int l = Math.min(twoReadableBytes - index, length); - read += two.getBytes(index, out, l); - length -= l; - - if (length != 0) { - read += three.getBytes(threeReadIndex, out, length); - } - break; - } - case 0x4: - { - read += three.getBytes(index, out, length); - - break; - } - default: - throw new IllegalStateException(); - } - - return read; - } - - @Override - public int getBytes(int index, FileChannel out, long position, int length) throws IOException { - checkIndex(index, length); - int read = 0; - long ri = calculateRelativeIndex(index); - index = (int) (ri & Integer.MAX_VALUE); - switch ((int) ((ri & MASK) >>> 32L)) { - case 0x1: - { - int l = Math.min(oneReadableBytes - index, length); - read += one.getBytes(index, out, position, l); - length -= l; - position += l; - - if (length != 0) { - l = Math.min(twoReadableBytes, length); - read += two.getBytes(twoReadIndex, out, position, l); - length -= l; - position += l; - - if (length != 0) { - read += three.getBytes(threeReadIndex, out, position, length); - } - } - break; - } - case 0x2: - { - int l = Math.min(twoReadableBytes - index, length); - read += two.getBytes(index, out, position, l); - length -= l; - position += l; - - if (length != 0) { - read += three.getBytes(threeReadIndex, out, position, length); - } - break; - } - case 0x4: - { - read += three.getBytes(index, out, position, length); - - break; - } - default: - throw new IllegalStateException(); - } - - return read; - } - - @Override - public ByteBuf copy(int index, int length) { - checkIndex(index, length); - - ByteBuf buffer = allocator.buffer(length); - - if (index == 0 && length == capacity) { - buffer.writeBytes(one, oneReadIndex, oneReadableBytes); - buffer.writeBytes(two, twoReadIndex, twoReadableBytes); - buffer.writeBytes(three, threeReadIndex, threeReadableBytes); - - return buffer; - } - - long ri = calculateRelativeIndex(index); - index = (int) (ri & Integer.MAX_VALUE); - - switch ((int) ((ri & MASK) >>> 32L)) { - case 0x1: - { - int l = Math.min(oneReadableBytes - index, length); - buffer.writeBytes(one, index, l); - length -= l; - - if (length != 0) { - l = Math.min(twoReadableBytes, length); - buffer.writeBytes(two, twoReadIndex, l); - length -= l; - if (length != 0) { - buffer.writeBytes(three, threeReadIndex, length); - } - } - - return buffer; - } - case 0x2: - { - int l = Math.min(twoReadableBytes - index, length); - buffer.writeBytes(two, index, l); - length -= l; - - if (length != 0) { - buffer.writeBytes(three, threeReadIndex, length); - } - - return buffer; - } - case 0x4: - { - buffer.writeBytes(three, index, length); - - return buffer; - } - default: - throw new IllegalStateException(); - } - } - - @Override - public ByteBuf retainedSlice() { - return new Tuple3ByteBuf( - allocator, - one.retainedSlice(oneReadIndex, oneReadableBytes), - two.retainedSlice(twoReadIndex, twoReadableBytes), - three.retainedSlice(threeReadIndex, threeReadableBytes)); - } - - @Override - public ByteBuf slice(final int readIndex, int length) { - checkIndex(readIndex, length); - - if (readIndex == 0 && length == capacity) { - return new Tuple3ByteBuf( - allocator, - one.slice(oneReadIndex, oneReadableBytes), - two.slice(twoReadIndex, twoReadableBytes), - three.slice(threeReadIndex, threeReadableBytes)); - } - - long ri = calculateRelativeIndex(readIndex); - int index = (int) (ri & Integer.MAX_VALUE); - switch ((int) ((ri & MASK) >>> 32L)) { - case 0x1: - { - ByteBuf oneSlice; - ByteBuf twoSlice; - ByteBuf threeSlice; - - int l = Math.min(oneReadableBytes - index, length); - oneSlice = one.slice(index, l); - length -= l; - if (length != 0) { - l = Math.min(twoReadableBytes, length); - twoSlice = two.slice(twoReadIndex, l); - length -= l; - if (length != 0) { - threeSlice = three.slice(threeReadIndex, length); - return new Tuple3ByteBuf(allocator, oneSlice, twoSlice, threeSlice); - } else { - return new Tuple2ByteBuf(allocator, oneSlice, twoSlice); - } - - } else { - return oneSlice; - } - } - case 0x2: - { - ByteBuf twoSlice; - ByteBuf threeSlice; - - int l = Math.min(twoReadableBytes - index, length); - twoSlice = two.slice(index, l); - length -= l; - if (length != 0) { - threeSlice = three.slice(threeReadIndex, length); - return new Tuple2ByteBuf(allocator, twoSlice, threeSlice); - } else { - return twoSlice; - } - } - case 0x4: - { - return three.slice(index, length); - } - default: - throw new IllegalStateException(); - } - } - - @Override - protected void deallocate() { - if (freed) { - return; - } - - freed = true; - ReferenceCountUtil.safeRelease(one); - ReferenceCountUtil.safeRelease(two); - ReferenceCountUtil.safeRelease(three); - } - - @Override - public String toString(Charset charset) { - StringBuilder builder = new StringBuilder(3); - builder.append(one.toString(charset)); - builder.append(two.toString(charset)); - builder.append(three.toString(charset)); - return builder.toString(); - } - - @Override - public String toString() { - return "Tuple3ByteBuf{" - + "capacity=" - + capacity - + ", one=" - + one - + ", two=" - + two - + ", three=" - + three - + ", allocator=" - + allocator - + ", oneReadIndex=" - + oneReadIndex - + ", twoReadIndex=" - + twoReadIndex - + ", threeReadIndex=" - + threeReadIndex - + ", oneReadableBytes=" - + oneReadableBytes - + ", twoReadableBytes=" - + twoReadableBytes - + ", threeReadableBytes=" - + threeReadableBytes - + ", twoRelativeIndex=" - + twoRelativeIndex - + ", threeRelativeIndex=" - + threeRelativeIndex - + '}'; - } -} diff --git a/rsocket-core/src/main/java/io/rsocket/buffer/TupleByteBuf.java b/rsocket-core/src/main/java/io/rsocket/buffer/TupleByteBuf.java deleted file mode 100644 index 8c8e2e7e4..000000000 --- a/rsocket-core/src/main/java/io/rsocket/buffer/TupleByteBuf.java +++ /dev/null @@ -1,35 +0,0 @@ -package io.rsocket.buffer; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import java.util.Objects; - -public abstract class TupleByteBuf { - - private TupleByteBuf() {} - - public static ByteBuf of(ByteBuf one, ByteBuf two) { - return of(ByteBufAllocator.DEFAULT, one, two); - } - - public static ByteBuf of(ByteBufAllocator allocator, ByteBuf one, ByteBuf two) { - Objects.requireNonNull(allocator); - Objects.requireNonNull(one); - Objects.requireNonNull(two); - - return new Tuple2ByteBuf(allocator, one, two); - } - - public static ByteBuf of(ByteBuf one, ByteBuf two, ByteBuf three) { - return of(ByteBufAllocator.DEFAULT, one, two, three); - } - - public static ByteBuf of(ByteBufAllocator allocator, ByteBuf one, ByteBuf two, ByteBuf three) { - Objects.requireNonNull(allocator); - Objects.requireNonNull(one); - Objects.requireNonNull(two); - Objects.requireNonNull(three); - - return new Tuple3ByteBuf(allocator, one, two, three); - } -} diff --git a/rsocket-core/src/test/java/io/rsocket/buffer/Tuple3ByteBufTest.java b/rsocket-core/src/test/java/io/rsocket/buffer/Tuple3ByteBufTest.java deleted file mode 100644 index 4515fb29b..000000000 --- a/rsocket-core/src/test/java/io/rsocket/buffer/Tuple3ByteBufTest.java +++ /dev/null @@ -1,98 +0,0 @@ -package io.rsocket.buffer; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.util.concurrent.ThreadLocalRandom; -import org.junit.Assert; -import org.junit.jupiter.api.Test; - -class Tuple3ByteBufTest { - @Test - void testTupleBufferGet() { - ByteBufAllocator allocator = ByteBufAllocator.DEFAULT; - ByteBuf one = allocator.directBuffer(9); - - byte[] bytes = new byte[9]; - ThreadLocalRandom.current().nextBytes(bytes); - one.writeBytes(bytes); - - bytes = new byte[8]; - ThreadLocalRandom.current().nextBytes(bytes); - ByteBuf two = Unpooled.wrappedBuffer(bytes); - - bytes = new byte[9]; - ThreadLocalRandom.current().nextBytes(bytes); - ByteBuf three = Unpooled.wrappedBuffer(bytes); - - ByteBuf tuple = TupleByteBuf.of(one, two, three); - - int anInt = tuple.getInt(16); - - long aLong = tuple.getLong(15); - - short aShort = tuple.getShort(8); - - int medium = tuple.getMedium(8); - } - - @Test - void testTuple3BufferSlicing() { - ByteBufAllocator allocator = ByteBufAllocator.DEFAULT; - ByteBuf one = allocator.directBuffer(); - ByteBufUtil.writeUtf8(one, "foo"); - - ByteBuf two = allocator.directBuffer(); - ByteBufUtil.writeUtf8(two, "bar"); - - ByteBuf three = allocator.directBuffer(); - ByteBufUtil.writeUtf8(three, "bar"); - - ByteBuf buf = TupleByteBuf.of(one, two, three); - - String s = buf.slice(0, 6).toString(Charset.defaultCharset()); - Assert.assertEquals("foobar", s); - - String s1 = buf.slice(3, 6).toString(Charset.defaultCharset()); - Assert.assertEquals("barbar", s1); - - String s2 = buf.slice(4, 4).toString(Charset.defaultCharset()); - Assert.assertEquals("arba", s2); - } - - @Test - void testTuple3ToNioBuffers() throws Exception { - ByteBufAllocator allocator = ByteBufAllocator.DEFAULT; - ByteBuf one = allocator.directBuffer(); - ByteBufUtil.writeUtf8(one, "one"); - - ByteBuf two = allocator.directBuffer(); - ByteBufUtil.writeUtf8(two, "two"); - - ByteBuf three = allocator.directBuffer(); - ByteBufUtil.writeUtf8(three, "three"); - - ByteBuf buf = TupleByteBuf.of(one, two, three); - ByteBuffer[] byteBuffers = buf.nioBuffers(); - - Assert.assertEquals(3, byteBuffers.length); - - ByteBuffer bb = byteBuffers[0]; - byte[] dst = new byte[bb.remaining()]; - bb.get(dst); - Assert.assertEquals("one", new String(dst, "UTF-8")); - - bb = byteBuffers[1]; - dst = new byte[bb.remaining()]; - bb.get(dst); - Assert.assertEquals("two", new String(dst, "UTF-8")); - - bb = byteBuffers[2]; - dst = new byte[bb.remaining()]; - bb.get(dst); - Assert.assertEquals("three", new String(dst, "UTF-8")); - } -} From d3dc85f32ec12e553c382dda28e8c3ba114f95aa Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Thu, 30 Apr 2020 08:52:52 +0100 Subject: [PATCH 06/25] Deprecate AbstractRSocket and provide alternative (#805) --- .../main/java/io/rsocket/AbstractRSocket.java | 35 +-------- .../src/main/java/io/rsocket/RSocket.java | 37 +++++++-- .../main/java/io/rsocket/SocketAcceptor.java | 54 ++++++++++++- .../io/rsocket/core/RSocketConnector.java | 3 +- .../java/io/rsocket/core/RSocketServer.java | 3 +- .../io/rsocket/core/RSocketResponderTest.java | 27 ++++--- .../java/io/rsocket/core/RSocketTest.java | 13 ++-- .../tcp/channel/ChannelEchoClient.java | 31 +++----- .../transport/tcp/duplex/DuplexClient.java | 23 +++--- .../transport/tcp/lease/LeaseExample.java | 19 ++--- .../tcp/requestresponse/HelloWorldClient.java | 33 ++++---- .../tcp/resume/ResumeFileTransfer.java | 50 +++++-------- .../transport/tcp/stream/StreamingClient.java | 23 ++---- .../transport/ws/WebSocketHeadersSample.java | 43 +++++------ .../rsocket/integration/IntegrationTest.java | 5 +- .../integration/InteractionsLoadTest.java | 8 +- .../integration/TcpIntegrationTest.java | 13 ++-- .../rsocket/integration/TestingStreaming.java | 75 ++++++------------- .../rsocket/resume/ResumeIntegrationTest.java | 8 +- .../client/LoadBalancedRSocketMono.java | 18 ++++- .../java/io/rsocket/test/PingHandler.java | 3 +- .../java/io/rsocket/test/TestRSocket.java | 4 +- .../io/rsocket/integration/FragmentTest.java | 9 +-- .../WebSocketTransportIntegrationTest.java | 17 +---- .../WebsocketPingPongIntegrationTest.java | 12 +-- 25 files changed, 264 insertions(+), 302 deletions(-) diff --git a/rsocket-core/src/main/java/io/rsocket/AbstractRSocket.java b/rsocket-core/src/main/java/io/rsocket/AbstractRSocket.java index c099a3120..7f39956dc 100644 --- a/rsocket-core/src/main/java/io/rsocket/AbstractRSocket.java +++ b/rsocket-core/src/main/java/io/rsocket/AbstractRSocket.java @@ -16,48 +16,21 @@ package io.rsocket; -import org.reactivestreams.Publisher; -import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.publisher.MonoProcessor; /** * An abstract implementation of {@link RSocket}. All request handling methods emit {@link * UnsupportedOperationException} and hence must be overridden to provide a valid implementation. + * + * @deprecated as of 1.0 in favor of implementing {@link RSocket} directly which has default + * methods. */ +@Deprecated public abstract class AbstractRSocket implements RSocket { private final MonoProcessor onClose = MonoProcessor.create(); - @Override - public Mono fireAndForget(Payload payload) { - payload.release(); - return Mono.error(new UnsupportedOperationException("Fire and forget not implemented.")); - } - - @Override - public Mono requestResponse(Payload payload) { - payload.release(); - return Mono.error(new UnsupportedOperationException("Request-Response not implemented.")); - } - - @Override - public Flux requestStream(Payload payload) { - payload.release(); - return Flux.error(new UnsupportedOperationException("Request-Stream not implemented.")); - } - - @Override - public Flux requestChannel(Publisher payloads) { - return Flux.error(new UnsupportedOperationException("Request-Channel not implemented.")); - } - - @Override - public Mono metadataPush(Payload payload) { - payload.release(); - return Mono.error(new UnsupportedOperationException("Metadata-Push not implemented.")); - } - @Override public void dispose() { onClose.onComplete(); diff --git a/rsocket-core/src/main/java/io/rsocket/RSocket.java b/rsocket-core/src/main/java/io/rsocket/RSocket.java index 5468b4de8..773c93dc2 100644 --- a/rsocket-core/src/main/java/io/rsocket/RSocket.java +++ b/rsocket-core/src/main/java/io/rsocket/RSocket.java @@ -33,7 +33,10 @@ public interface RSocket extends Availability, Closeable { * @return {@code Publisher} that completes when the passed {@code payload} is successfully * handled, otherwise errors. */ - Mono fireAndForget(Payload payload); + default Mono fireAndForget(Payload payload) { + payload.release(); + return Mono.error(new UnsupportedOperationException("Fire-and-Forget not implemented.")); + } /** * Request-Response interaction model of {@code RSocket}. @@ -42,7 +45,10 @@ public interface RSocket extends Availability, Closeable { * @return {@code Publisher} containing at most a single {@code Payload} representing the * response. */ - Mono requestResponse(Payload payload); + default Mono requestResponse(Payload payload) { + payload.release(); + return Mono.error(new UnsupportedOperationException("Request-Response not implemented.")); + } /** * Request-Stream interaction model of {@code RSocket}. @@ -50,7 +56,10 @@ public interface RSocket extends Availability, Closeable { * @param payload Request payload. * @return {@code Publisher} containing the stream of {@code Payload}s representing the response. */ - Flux requestStream(Payload payload); + default Flux requestStream(Payload payload) { + payload.release(); + return Flux.error(new UnsupportedOperationException("Request-Stream not implemented.")); + } /** * Request-Channel interaction model of {@code RSocket}. @@ -58,7 +67,9 @@ public interface RSocket extends Availability, Closeable { * @param payloads Stream of request payloads. * @return Stream of response payloads. */ - Flux requestChannel(Publisher payloads); + default Flux requestChannel(Publisher payloads) { + return Flux.error(new UnsupportedOperationException("Request-Channel not implemented.")); + } /** * Metadata-Push interaction model of {@code RSocket}. @@ -67,10 +78,26 @@ public interface RSocket extends Availability, Closeable { * @return {@code Publisher} that completes when the passed {@code payload} is successfully * handled, otherwise errors. */ - Mono metadataPush(Payload payload); + default Mono metadataPush(Payload payload) { + payload.release(); + return Mono.error(new UnsupportedOperationException("Metadata-Push not implemented.")); + } @Override default double availability() { return isDisposed() ? 0.0 : 1.0; } + + @Override + default void dispose() {} + + @Override + default boolean isDisposed() { + return false; + } + + @Override + default Mono onClose() { + return Mono.never(); + } } diff --git a/rsocket-core/src/main/java/io/rsocket/SocketAcceptor.java b/rsocket-core/src/main/java/io/rsocket/SocketAcceptor.java index 85c731eea..a42626e78 100644 --- a/rsocket-core/src/main/java/io/rsocket/SocketAcceptor.java +++ b/rsocket-core/src/main/java/io/rsocket/SocketAcceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2018 the original author or authors. + * Copyright 2015-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,9 @@ package io.rsocket; import io.rsocket.exceptions.SetupException; +import java.util.function.Function; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; /** @@ -38,4 +41,53 @@ public interface SocketAcceptor { * @throws SetupException If the acceptor needs to reject the setup of this socket. */ Mono accept(ConnectionSetupPayload setup, RSocket sendingSocket); + + /** Create a {@code SocketAcceptor} that handles requests with the given {@code RSocket}. */ + static SocketAcceptor with(RSocket rsocket) { + return (setup, sendingRSocket) -> Mono.just(rsocket); + } + + /** Create a {@code SocketAcceptor} for fire-and-forget interactions with the given handler. */ + static SocketAcceptor forFireAndForget(Function> handler) { + return with( + new RSocket() { + @Override + public Mono fireAndForget(Payload payload) { + return handler.apply(payload); + } + }); + } + + /** Create a {@code SocketAcceptor} for request-response interactions with the given handler. */ + static SocketAcceptor forRequestResponse(Function> handler) { + return with( + new RSocket() { + @Override + public Mono requestResponse(Payload payload) { + return handler.apply(payload); + } + }); + } + + /** Create a {@code SocketAcceptor} for request-stream interactions with the given handler. */ + static SocketAcceptor forRequestStream(Function> handler) { + return with( + new RSocket() { + @Override + public Flux requestStream(Payload payload) { + return handler.apply(payload); + } + }); + } + + /** Create a {@code SocketAcceptor} for request-channel interactions with the given handler. */ + static SocketAcceptor forRequestChannel(Function, Flux> handler) { + return with( + new RSocket() { + @Override + public Flux requestChannel(Publisher payloads) { + return handler.apply(payloads); + } + }); + } } diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java index 57aebbdf0..a7eed8c76 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java @@ -17,7 +17,6 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import io.rsocket.AbstractRSocket; import io.rsocket.ConnectionSetupPayload; import io.rsocket.DuplexConnection; import io.rsocket.Payload; @@ -56,7 +55,7 @@ public class RSocketConnector { private String metadataMimeType = "application/binary"; private String dataMimeType = "application/binary"; - private SocketAcceptor acceptor = (setup, sendingSocket) -> Mono.just(new AbstractRSocket() {}); + private SocketAcceptor acceptor = SocketAcceptor.with(new RSocket() {}); private InitializingInterceptorRegistry interceptors = new InitializingInterceptorRegistry(); private Duration keepAliveInterval = Duration.ofSeconds(20); diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java index c82a2f40a..19f0c5008 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java @@ -17,7 +17,6 @@ package io.rsocket.core; import io.netty.buffer.ByteBuf; -import io.rsocket.AbstractRSocket; import io.rsocket.Closeable; import io.rsocket.ConnectionSetupPayload; import io.rsocket.DuplexConnection; @@ -45,7 +44,7 @@ public final class RSocketServer { private static final String SERVER_TAG = "server"; private static final int MIN_MTU_SIZE = 64; - private SocketAcceptor acceptor = (setup, sendingSocket) -> Mono.just(new AbstractRSocket() {}); + private SocketAcceptor acceptor = SocketAcceptor.with(new RSocket() {}); private InitializingInterceptorRegistry interceptors = new InitializingInterceptorRegistry(); private int mtu = 0; diff --git a/rsocket-core/src/test/java/io/rsocket/core/RSocketResponderTest.java b/rsocket-core/src/test/java/io/rsocket/core/RSocketResponderTest.java index c19456548..2dbf6715b 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/RSocketResponderTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/RSocketResponderTest.java @@ -35,7 +35,6 @@ import io.netty.util.CharsetUtil; import io.netty.util.ReferenceCountUtil; import io.netty.util.ReferenceCounted; -import io.rsocket.AbstractRSocket; import io.rsocket.Payload; import io.rsocket.RSocket; import io.rsocket.frame.CancelFrameFlyweight; @@ -164,7 +163,7 @@ public void testCancel() { final int streamId = 4; final AtomicBoolean cancelled = new AtomicBoolean(); rule.setAcceptingSocket( - new AbstractRSocket() { + new RSocket() { @Override public Mono requestResponse(Payload payload) { payload.release(); @@ -193,8 +192,8 @@ public void shouldThrownExceptionIfGivenPayloadIsExitsSizeAllowanceWithNoFragmen ThreadLocalRandom.current().nextBytes(metadata); ThreadLocalRandom.current().nextBytes(data); final Payload payload = DefaultPayload.create(data, metadata); - final AbstractRSocket acceptingSocket = - new AbstractRSocket() { + final RSocket acceptingSocket = + new RSocket() { @Override public Mono requestResponse(Payload p) { p.release(); @@ -256,7 +255,7 @@ public void checkNoLeaksOnRacingCancelFromRequestChannelAndNextFromUpstream() { AssertSubscriber assertSubscriber = AssertSubscriber.create(); rule.setAcceptingSocket( - new AbstractRSocket() { + new RSocket() { @Override public Flux requestChannel(Publisher payloads) { payloads.subscribe(assertSubscriber); @@ -312,7 +311,7 @@ public void checkNoLeaksOnRacingBetweenDownstreamCancelAndOnNextFromRequestChann FluxSink[] sinks = new FluxSink[1]; rule.setAcceptingSocket( - new AbstractRSocket() { + new RSocket() { @Override public Flux requestChannel(Publisher payloads) { ((Flux) payloads) @@ -352,7 +351,7 @@ public void checkNoLeaksOnRacingBetweenDownstreamCancelAndOnNextFromRequestChann FluxSink[] sinks = new FluxSink[1]; rule.setAcceptingSocket( - new AbstractRSocket() { + new RSocket() { @Override public Flux requestChannel(Publisher payloads) { ((Flux) payloads) @@ -397,7 +396,7 @@ public Flux requestChannel(Publisher payloads) { FluxSink[] sinks = new FluxSink[1]; AssertSubscriber assertSubscriber = AssertSubscriber.create(); rule.setAcceptingSocket( - new AbstractRSocket() { + new RSocket() { @Override public Flux requestChannel(Publisher payloads) { payloads.subscribe(assertSubscriber); @@ -466,7 +465,7 @@ public void checkNoLeaksOnRacingBetweenDownstreamCancelAndOnNextFromRequestStrea FluxSink[] sinks = new FluxSink[1]; rule.setAcceptingSocket( - new AbstractRSocket() { + new RSocket() { @Override public Flux requestStream(Payload payload) { payload.release(); @@ -503,7 +502,7 @@ public void checkNoLeaksOnRacingBetweenDownstreamCancelAndOnNextFromRequestRespo Operators.MonoSubscriber[] sources = new Operators.MonoSubscriber[1]; rule.setAcceptingSocket( - new AbstractRSocket() { + new RSocket() { @Override public Mono requestResponse(Payload payload) { payload.release(); @@ -540,7 +539,7 @@ public void simpleDiscardRequestStreamTest() { FluxSink[] sinks = new FluxSink[1]; rule.setAcceptingSocket( - new AbstractRSocket() { + new RSocket() { @Override public Flux requestStream(Payload payload) { payload.release(); @@ -569,7 +568,7 @@ public void simpleDiscardRequestChannelTest() { ByteBufAllocator allocator = rule.alloc(); rule.setAcceptingSocket( - new AbstractRSocket() { + new RSocket() { @Override public Flux requestChannel(Publisher payloads) { return (Flux) payloads; @@ -619,7 +618,7 @@ public void verifiesThatFrameWithNoMetadataHasDecodedCorrectlyIntoPayload( TestPublisher testPublisher = TestPublisher.create(); rule.setAcceptingSocket( - new AbstractRSocket() { + new RSocket() { @Override public Mono fireAndForget(Payload payload) { Mono.just(payload).subscribe(assertSubscriber); @@ -720,7 +719,7 @@ public static class ServerSocketRule extends AbstractSocketRule requestResponse(Payload payload) { return Mono.just(payload); diff --git a/rsocket-core/src/test/java/io/rsocket/core/RSocketTest.java b/rsocket-core/src/test/java/io/rsocket/core/RSocketTest.java index 4a2c43ef8..02c3dfca8 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/RSocketTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/RSocketTest.java @@ -23,7 +23,6 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; -import io.rsocket.AbstractRSocket; import io.rsocket.Payload; import io.rsocket.RSocket; import io.rsocket.buffer.LeaksTrackingByteBufAllocator; @@ -83,7 +82,7 @@ public void testRequestReplyNoError() { @Test(timeout = 2000) public void testHandlerEmitsError() { rule.setRequestAcceptor( - new AbstractRSocket() { + new RSocket() { @Override public Mono requestResponse(Payload payload) { return Mono.error(new NullPointerException("Deliberate exception.")); @@ -102,7 +101,7 @@ public Mono requestResponse(Payload payload) { @Test(timeout = 2000) public void testHandlerEmitsCustomError() { rule.setRequestAcceptor( - new AbstractRSocket() { + new RSocket() { @Override public Mono requestResponse(Payload payload) { return Mono.error( @@ -129,7 +128,7 @@ public Mono requestResponse(Payload payload) { @Test(timeout = 2000) public void testRequestPropagatesCorrectlyForRequestChannel() { rule.setRequestAcceptor( - new AbstractRSocket() { + new RSocket() { @Override public Flux requestChannel(Publisher payloads) { return Flux.from(payloads) @@ -170,7 +169,7 @@ public void testChannel() throws Exception { public void testErrorPropagatesCorrectly() { AtomicReference error = new AtomicReference<>(); rule.setRequestAcceptor( - new AbstractRSocket() { + new RSocket() { @Override public Flux requestChannel(Publisher payloads) { return Flux.from(payloads).doOnError(error::set); @@ -291,7 +290,7 @@ void initRequestChannelCase( TestPublisher responderPublisher, AssertSubscriber responderSubscriber) { rule.setRequestAcceptor( - new AbstractRSocket() { + new RSocket() { @Override public Flux requestChannel(Publisher payloads) { payloads.subscribe(responderSubscriber); @@ -446,7 +445,7 @@ protected void init() { requestAcceptor = null != requestAcceptor ? requestAcceptor - : new AbstractRSocket() { + : new RSocket() { @Override public Mono requestResponse(Payload payload) { return Mono.just(payload); diff --git a/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/channel/ChannelEchoClient.java b/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/channel/ChannelEchoClient.java index 71e48790f..b532c0140 100644 --- a/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/channel/ChannelEchoClient.java +++ b/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/channel/ChannelEchoClient.java @@ -16,8 +16,6 @@ package io.rsocket.examples.transport.tcp.channel; -import io.rsocket.AbstractRSocket; -import io.rsocket.ConnectionSetupPayload; import io.rsocket.Payload; import io.rsocket.RSocket; import io.rsocket.SocketAcceptor; @@ -27,18 +25,25 @@ import io.rsocket.transport.netty.server.TcpServerTransport; import io.rsocket.util.DefaultPayload; import java.time.Duration; -import org.reactivestreams.Publisher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; public final class ChannelEchoClient { private static final Logger logger = LoggerFactory.getLogger(ChannelEchoClient.class); public static void main(String[] args) { - RSocketServer.create(new EchoAcceptor()) + + SocketAcceptor echoAcceptor = + SocketAcceptor.forRequestChannel( + payloads -> + Flux.from(payloads) + .map(Payload::getDataUtf8) + .map(s -> "Echo: " + s) + .map(DefaultPayload::create)); + + RSocketServer.create(echoAcceptor) .bind(TcpServerTransport.create("localhost", 7000)) .subscribe(); @@ -55,20 +60,4 @@ public static void main(String[] args) { .then() .block(); } - - private static class EchoAcceptor implements SocketAcceptor { - @Override - public Mono accept(ConnectionSetupPayload setupPayload, RSocket reactiveSocket) { - return Mono.just( - new AbstractRSocket() { - @Override - public Flux requestChannel(Publisher payloads) { - return Flux.from(payloads) - .map(Payload::getDataUtf8) - .map(s -> "Echo: " + s) - .map(DefaultPayload::create); - } - }); - } - } } diff --git a/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/duplex/DuplexClient.java b/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/duplex/DuplexClient.java index bfa58bf40..3eba5a800 100644 --- a/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/duplex/DuplexClient.java +++ b/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/duplex/DuplexClient.java @@ -16,7 +16,8 @@ package io.rsocket.examples.transport.tcp.duplex; -import io.rsocket.AbstractRSocket; +import static io.rsocket.SocketAcceptor.forRequestStream; + import io.rsocket.Payload; import io.rsocket.RSocket; import io.rsocket.core.RSocketConnector; @@ -31,6 +32,7 @@ public final class DuplexClient { public static void main(String[] args) { + RSocketServer.create( (setup, rsocket) -> { rsocket @@ -39,26 +41,21 @@ public static void main(String[] args) { .log() .subscribe(); - return Mono.just(new AbstractRSocket() {}); + return Mono.just(new RSocket() {}); }) .bind(TcpServerTransport.create("localhost", 7000)) .subscribe(); - RSocket socket = + RSocket rsocket = RSocketConnector.create() .acceptor( - (setup, rsocket) -> - Mono.just( - new AbstractRSocket() { - @Override - public Flux requestStream(Payload payload) { - return Flux.interval(Duration.ofSeconds(1)) - .map(aLong -> DefaultPayload.create("Bi-di Response => " + aLong)); - } - })) + forRequestStream( + payload -> + Flux.interval(Duration.ofSeconds(1)) + .map(aLong -> DefaultPayload.create("Bi-di Response => " + aLong)))) .connect(TcpClientTransport.create("localhost", 7000)) .block(); - socket.onClose().block(); + rsocket.onClose().block(); } } diff --git a/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/lease/LeaseExample.java b/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/lease/LeaseExample.java index a12c9a170..3eaebd89a 100644 --- a/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/lease/LeaseExample.java +++ b/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/lease/LeaseExample.java @@ -18,9 +18,9 @@ import static java.time.Duration.ofSeconds; -import io.rsocket.AbstractRSocket; import io.rsocket.Payload; import io.rsocket.RSocket; +import io.rsocket.SocketAcceptor; import io.rsocket.core.RSocketConnector; import io.rsocket.core.RSocketServer; import io.rsocket.lease.Lease; @@ -45,7 +45,7 @@ public static void main(String[] args) { CloseableChannel server = RSocketServer.create( - (setup, sendingRSocket) -> Mono.just(new ServerAcceptor(sendingRSocket))) + (setup, sendingRSocket) -> Mono.just(new ServerRSocket(sendingRSocket))) .lease( () -> Leases.create() @@ -62,7 +62,9 @@ public static void main(String[] args) { Leases.create() .sender(new LeaseSender(CLIENT_TAG, 3_000, 5)) .receiver(new LeaseReceiver(CLIENT_TAG))) - .acceptor((rSocket, setup) -> Mono.just(new ClientAcceptor())) + .acceptor( + SocketAcceptor.forRequestResponse( + payload -> Mono.just(DefaultPayload.create("Client Response " + new Date())))) .connect(TcpClientTransport.create(server.address())) .block(); @@ -133,17 +135,10 @@ private static class NoopStats implements LeaseStats { public void onEvent(EventType eventType) {} } - private static class ClientAcceptor extends AbstractRSocket { - @Override - public Mono requestResponse(Payload payload) { - return Mono.just(DefaultPayload.create("Client Response " + new Date())); - } - } - - private static class ServerAcceptor extends AbstractRSocket { + private static class ServerRSocket implements RSocket { private final RSocket senderRSocket; - public ServerAcceptor(RSocket senderRSocket) { + public ServerRSocket(RSocket senderRSocket) { this.senderRSocket = senderRSocket; } diff --git a/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/requestresponse/HelloWorldClient.java b/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/requestresponse/HelloWorldClient.java index 1b9994c2f..85faeee82 100644 --- a/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/requestresponse/HelloWorldClient.java +++ b/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/requestresponse/HelloWorldClient.java @@ -16,9 +16,9 @@ package io.rsocket.examples.transport.tcp.requestresponse; -import io.rsocket.AbstractRSocket; import io.rsocket.Payload; import io.rsocket.RSocket; +import io.rsocket.SocketAcceptor; import io.rsocket.core.RSocketConnector; import io.rsocket.core.RSocketServer; import io.rsocket.transport.netty.client.TcpClientTransport; @@ -33,22 +33,23 @@ public final class HelloWorldClient { private static final Logger logger = LoggerFactory.getLogger(HelloWorldClient.class); public static void main(String[] args) { - RSocketServer.create( - (setupPayload, reactiveSocket) -> - Mono.just( - new AbstractRSocket() { - boolean fail = true; - @Override - public Mono requestResponse(Payload p) { - if (fail) { - fail = false; - return Mono.error(new Throwable("Simulated error")); - } else { - return Mono.just(p); - } - } - })) + RSocket rsocket = + new RSocket() { + boolean fail = true; + + @Override + public Mono requestResponse(Payload p) { + if (fail) { + fail = false; + return Mono.error(new Throwable("Simulated error")); + } else { + return Mono.just(p); + } + } + }; + + RSocketServer.create(SocketAcceptor.with(rsocket)) .bind(TcpServerTransport.create("localhost", 7000)) .subscribe(); diff --git a/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/resume/ResumeFileTransfer.java b/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/resume/ResumeFileTransfer.java index d449dd205..93b54e146 100644 --- a/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/resume/ResumeFileTransfer.java +++ b/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/resume/ResumeFileTransfer.java @@ -16,9 +16,9 @@ package io.rsocket.examples.transport.tcp.resume; -import io.rsocket.AbstractRSocket; import io.rsocket.Payload; import io.rsocket.RSocket; +import io.rsocket.SocketAcceptor; import io.rsocket.core.RSocketConnector; import io.rsocket.core.RSocketServer; import io.rsocket.core.Resume; @@ -30,7 +30,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; import reactor.util.retry.Retry; public class ResumeFileTransfer { @@ -40,18 +39,31 @@ public class ResumeFileTransfer { private static final Logger logger = LoggerFactory.getLogger(ResumeFileTransfer.class); public static void main(String[] args) { - RequestCodec requestCodec = new RequestCodec(); + Resume resume = new Resume() .sessionDuration(Duration.ofMinutes(5)) .retry( Retry.fixedDelay(Long.MAX_VALUE, Duration.ofSeconds(1)) - .doBeforeRetry( - retrySignal -> - logger.debug("Disconnected. Trying to resume connection..."))); + .doBeforeRetry(s -> logger.debug("Disconnected. Trying to resume..."))); + + RequestCodec codec = new RequestCodec(); CloseableChannel server = - RSocketServer.create((setup, rSocket) -> Mono.just(new FileServer(requestCodec))) + RSocketServer.create( + SocketAcceptor.forRequestStream( + payload -> { + Request request = codec.decode(payload); + payload.release(); + String fileName = request.getFileName(); + int chunkSize = request.getChunkSize(); + + Flux ticks = Flux.interval(Duration.ofMillis(500)).onBackpressureDrop(); + + return Files.fileSource(fileName, chunkSize) + .map(DefaultPayload::create) + .zipWith(ticks, (p, tick) -> p); + })) .resume(resume) .bind(TcpServerTransport.create("localhost", 8000)) .block(); @@ -63,35 +75,13 @@ public static void main(String[] args) { .block(); client - .requestStream(requestCodec.encode(new Request(16, "lorem.txt"))) + .requestStream(codec.encode(new Request(16, "lorem.txt"))) .doFinally(s -> server.dispose()) .subscribe(Files.fileSink("rsocket-examples/out/lorem_output.txt", PREFETCH_WINDOW_SIZE)); server.onClose().block(); } - private static class FileServer extends AbstractRSocket { - private final RequestCodec requestCodec; - - public FileServer(RequestCodec requestCodec) { - this.requestCodec = requestCodec; - } - - @Override - public Flux requestStream(Payload payload) { - Request request = requestCodec.decode(payload); - payload.release(); - String fileName = request.getFileName(); - int chunkSize = request.getChunkSize(); - - Flux ticks = Flux.interval(Duration.ofMillis(500)).onBackpressureDrop(); - - return Files.fileSource(fileName, chunkSize) - .map(DefaultPayload::create) - .zipWith(ticks, (p, tick) -> p); - } - } - private static class RequestCodec { public Payload encode(Request request) { diff --git a/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/stream/StreamingClient.java b/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/stream/StreamingClient.java index 1ef2b7a90..6ac329d56 100644 --- a/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/stream/StreamingClient.java +++ b/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/stream/StreamingClient.java @@ -16,8 +16,6 @@ package io.rsocket.examples.transport.tcp.stream; -import io.rsocket.AbstractRSocket; -import io.rsocket.ConnectionSetupPayload; import io.rsocket.Payload; import io.rsocket.RSocket; import io.rsocket.SocketAcceptor; @@ -30,14 +28,17 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; public final class StreamingClient { private static final Logger logger = LoggerFactory.getLogger(StreamingClient.class); public static void main(String[] args) { - RSocketServer.create(new SocketAcceptorImpl()) + RSocketServer.create( + SocketAcceptor.forRequestStream( + payload -> + Flux.interval(Duration.ofMillis(100)) + .map(aLong -> DefaultPayload.create("Interval: " + aLong)))) .bind(TcpServerTransport.create("localhost", 7000)) .subscribe(); @@ -54,18 +55,4 @@ public static void main(String[] args) { .then() .block(); } - - private static class SocketAcceptorImpl implements SocketAcceptor { - @Override - public Mono accept(ConnectionSetupPayload setupPayload, RSocket reactiveSocket) { - return Mono.just( - new AbstractRSocket() { - @Override - public Flux requestStream(Payload payload) { - return Flux.interval(Duration.ofMillis(100)) - .map(aLong -> DefaultPayload.create("Interval: " + aLong)); - } - }); - } - } } diff --git a/rsocket-examples/src/main/java/io/rsocket/examples/transport/ws/WebSocketHeadersSample.java b/rsocket-examples/src/main/java/io/rsocket/examples/transport/ws/WebSocketHeadersSample.java index 24f029845..2ab73116d 100644 --- a/rsocket-examples/src/main/java/io/rsocket/examples/transport/ws/WebSocketHeadersSample.java +++ b/rsocket-examples/src/main/java/io/rsocket/examples/transport/ws/WebSocketHeadersSample.java @@ -17,8 +17,6 @@ package io.rsocket.examples.transport.ws; import io.netty.handler.codec.http.HttpResponseStatus; -import io.rsocket.AbstractRSocket; -import io.rsocket.ConnectionSetupPayload; import io.rsocket.DuplexConnection; import io.rsocket.Payload; import io.rsocket.RSocket; @@ -47,9 +45,8 @@ public class WebSocketHeadersSample { public static void main(String[] args) { ServerTransport.ConnectionAcceptor acceptor = - RSocketServer.create() + RSocketServer.create(SocketAcceptor.with(new ServerRSocket())) .payloadDecoder(PayloadDecoder.ZERO_COPY) - .acceptor(new SocketAcceptorImpl()) .asConnectionAcceptor(); DisposableServer disposableServer = @@ -114,29 +111,23 @@ public static void main(String[] args) { rSocket.requestResponse(payload1).block(); } - private static class SocketAcceptorImpl implements SocketAcceptor { + private static class ServerRSocket implements RSocket { + + @Override + public Mono fireAndForget(Payload payload) { + // System.out.println(payload.getDataUtf8()); + payload.release(); + return Mono.empty(); + } + + @Override + public Mono requestResponse(Payload payload) { + return Mono.just(payload); + } + @Override - public Mono accept(ConnectionSetupPayload setupPayload, RSocket reactiveSocket) { - return Mono.just( - new AbstractRSocket() { - - @Override - public Mono fireAndForget(Payload payload) { - // System.out.println(payload.getDataUtf8()); - payload.release(); - return Mono.empty(); - } - - @Override - public Mono requestResponse(Payload payload) { - return Mono.just(payload); - } - - @Override - public Flux requestChannel(Publisher payloads) { - return Flux.from(payloads).subscribeOn(Schedulers.single()); - } - }); + public Flux requestChannel(Publisher payloads) { + return Flux.from(payloads).subscribeOn(Schedulers.single()); } } } diff --git a/rsocket-examples/src/test/java/io/rsocket/integration/IntegrationTest.java b/rsocket-examples/src/test/java/io/rsocket/integration/IntegrationTest.java index 1ef7771cd..e2471f2fc 100644 --- a/rsocket-examples/src/test/java/io/rsocket/integration/IntegrationTest.java +++ b/rsocket-examples/src/test/java/io/rsocket/integration/IntegrationTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2018 the original author or authors. + * Copyright 2015-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,7 +23,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; -import io.rsocket.AbstractRSocket; import io.rsocket.Payload; import io.rsocket.RSocket; import io.rsocket.core.RSocketConnector; @@ -124,7 +123,7 @@ public void startup() { .subscribe(); return Mono.just( - new AbstractRSocket() { + new RSocket() { @Override public Mono requestResponse(Payload payload) { return Mono.just(DefaultPayload.create("RESPONSE", "METADATA")) diff --git a/rsocket-examples/src/test/java/io/rsocket/integration/InteractionsLoadTest.java b/rsocket-examples/src/test/java/io/rsocket/integration/InteractionsLoadTest.java index d24083ea6..48e5baaa7 100644 --- a/rsocket-examples/src/test/java/io/rsocket/integration/InteractionsLoadTest.java +++ b/rsocket-examples/src/test/java/io/rsocket/integration/InteractionsLoadTest.java @@ -1,8 +1,8 @@ package io.rsocket.integration; -import io.rsocket.AbstractRSocket; import io.rsocket.Payload; import io.rsocket.RSocket; +import io.rsocket.SocketAcceptor; import io.rsocket.core.RSocketConnector; import io.rsocket.core.RSocketServer; import io.rsocket.test.SlowTest; @@ -15,7 +15,6 @@ import org.junit.jupiter.api.Test; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; public class InteractionsLoadTest { @@ -23,7 +22,7 @@ public class InteractionsLoadTest { @SlowTest public void channel() { CloseableChannel server = - RSocketServer.create((setup, rsocket) -> Mono.just(new EchoRSocket())) + RSocketServer.create(SocketAcceptor.with(new EchoRSocket())) .bind(TcpServerTransport.create("localhost", 0)) .block(Duration.ofSeconds(10)); @@ -66,7 +65,8 @@ private static Flux input() { return interval; } - private static class EchoRSocket extends AbstractRSocket { + private static class EchoRSocket implements RSocket { + @Override public Flux requestChannel(Publisher payloads) { return Flux.from(payloads) diff --git a/rsocket-examples/src/test/java/io/rsocket/integration/TcpIntegrationTest.java b/rsocket-examples/src/test/java/io/rsocket/integration/TcpIntegrationTest.java index 7133820ca..de27bcb9b 100644 --- a/rsocket-examples/src/test/java/io/rsocket/integration/TcpIntegrationTest.java +++ b/rsocket-examples/src/test/java/io/rsocket/integration/TcpIntegrationTest.java @@ -19,7 +19,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import io.rsocket.AbstractRSocket; import io.rsocket.Payload; import io.rsocket.RSocket; import io.rsocket.core.RSocketConnector; @@ -41,7 +40,7 @@ import reactor.core.scheduler.Schedulers; public class TcpIntegrationTest { - private AbstractRSocket handler; + private RSocket handler; private CloseableChannel server; @@ -65,7 +64,7 @@ public void cleanup() { @Test(timeout = 15_000L) public void testCompleteWithoutNext() { handler = - new AbstractRSocket() { + new RSocket() { @Override public Flux requestStream(Payload payload) { return Flux.empty(); @@ -81,7 +80,7 @@ public Flux requestStream(Payload payload) { @Test(timeout = 15_000L) public void testSingleStream() { handler = - new AbstractRSocket() { + new RSocket() { @Override public Flux requestStream(Payload payload) { return Flux.just(DefaultPayload.create("RESPONSE", "METADATA")); @@ -98,7 +97,7 @@ public Flux requestStream(Payload payload) { @Test(timeout = 15_000L) public void testZeroPayload() { handler = - new AbstractRSocket() { + new RSocket() { @Override public Flux requestStream(Payload payload) { return Flux.just(EmptyPayload.INSTANCE); @@ -115,7 +114,7 @@ public Flux requestStream(Payload payload) { @Test(timeout = 15_000L) public void testRequestResponseErrors() { handler = - new AbstractRSocket() { + new RSocket() { boolean first = true; @Override @@ -155,7 +154,7 @@ public void testTwoConcurrentStreams() throws InterruptedException { map.put("REQUEST2", processor2); handler = - new AbstractRSocket() { + new RSocket() { @Override public Flux requestStream(Payload payload) { return map.get(payload.getDataUtf8()); diff --git a/rsocket-examples/src/test/java/io/rsocket/integration/TestingStreaming.java b/rsocket-examples/src/test/java/io/rsocket/integration/TestingStreaming.java index 8fe09430a..7d34ba478 100644 --- a/rsocket-examples/src/test/java/io/rsocket/integration/TestingStreaming.java +++ b/rsocket-examples/src/test/java/io/rsocket/integration/TestingStreaming.java @@ -16,9 +16,9 @@ package io.rsocket.integration; -import io.rsocket.AbstractRSocket; import io.rsocket.Closeable; import io.rsocket.Payload; +import io.rsocket.SocketAcceptor; import io.rsocket.core.RSocketConnector; import io.rsocket.core.RSocketServer; import io.rsocket.exceptions.ApplicationErrorException; @@ -29,7 +29,6 @@ import java.util.concurrent.atomic.AtomicInteger; import org.junit.Test; import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; public class TestingStreaming { LocalServerTransport serverTransport = LocalServerTransport.create("test"); @@ -40,27 +39,17 @@ public void testRangeButThrowException() { try { server = RSocketServer.create( - (connectionSetupPayload, rSocket) -> - Mono.just( - new AbstractRSocket() { - @Override - public double availability() { - return 1.0; - } - - @Override - public Flux requestStream(Payload payload) { - return Flux.range(1, 1000) - .doOnNext( - i -> { - if (i > 3) { - throw new RuntimeException("BOOM!"); - } - }) - .map(l -> DefaultPayload.create("l -> " + l)) - .cast(Payload.class); - } - })) + SocketAcceptor.forRequestStream( + payload -> + Flux.range(1, 1000) + .doOnNext( + i -> { + if (i > 3) { + throw new RuntimeException("BOOM!"); + } + }) + .map(l -> DefaultPayload.create("l -> " + l)) + .cast(Payload.class))) .bind(serverTransport) .block(); @@ -78,21 +67,11 @@ public void testRangeOfConsumers() { try { server = RSocketServer.create( - (connectionSetupPayload, rSocket) -> - Mono.just( - new AbstractRSocket() { - @Override - public double availability() { - return 1.0; - } - - @Override - public Flux requestStream(Payload payload) { - return Flux.range(1, 1000) - .map(l -> DefaultPayload.create("l -> " + l)) - .cast(Payload.class); - } - })) + SocketAcceptor.forRequestStream( + payload -> + Flux.range(1, 1000) + .map(l -> DefaultPayload.create("l -> " + l)) + .cast(Payload.class))) .bind(serverTransport) .block(); @@ -121,21 +100,11 @@ public void testSingleConsumer() { try { server = RSocketServer.create( - (connectionSetupPayload, rSocket) -> - Mono.just( - new AbstractRSocket() { - @Override - public double availability() { - return 1.0; - } - - @Override - public Flux requestStream(Payload payload) { - return Flux.range(1, 10_000) - .map(l -> DefaultPayload.create("l -> " + l)) - .cast(Payload.class); - } - })) + SocketAcceptor.forRequestStream( + payload -> + Flux.range(1, 10_000) + .map(l -> DefaultPayload.create("l -> " + l)) + .cast(Payload.class))) .bind(serverTransport) .block(); diff --git a/rsocket-examples/src/test/java/io/rsocket/resume/ResumeIntegrationTest.java b/rsocket-examples/src/test/java/io/rsocket/resume/ResumeIntegrationTest.java index bd2db39c7..b2dad0022 100644 --- a/rsocket-examples/src/test/java/io/rsocket/resume/ResumeIntegrationTest.java +++ b/rsocket-examples/src/test/java/io/rsocket/resume/ResumeIntegrationTest.java @@ -16,9 +16,9 @@ package io.rsocket.resume; -import io.rsocket.AbstractRSocket; import io.rsocket.Payload; import io.rsocket.RSocket; +import io.rsocket.SocketAcceptor; import io.rsocket.core.RSocketConnector; import io.rsocket.core.RSocketServer; import io.rsocket.core.Resume; @@ -127,7 +127,7 @@ public void reconnectOnMissingSession() { @Test void serverMissingResume() { CloseableChannel closeableChannel = - RSocketServer.create((setupPayload, rSocket) -> Mono.just(new TestResponderRSocket())) + RSocketServer.create(SocketAcceptor.with(new TestResponderRSocket())) .bind(serverTransport(SERVER_HOST, SERVER_PORT)) .block(); @@ -194,7 +194,7 @@ private static Mono newServerRSocket() { } private static Mono newServerRSocket(int sessionDurationSeconds) { - return RSocketServer.create((setup, rsocket) -> Mono.just(new TestResponderRSocket())) + return RSocketServer.create(SocketAcceptor.with(new TestResponderRSocket())) .resume( new Resume() .sessionDuration(Duration.ofSeconds(sessionDurationSeconds)) @@ -203,7 +203,7 @@ private static Mono newServerRSocket(int sessionDurationSecond .bind(serverTransport(SERVER_HOST, SERVER_PORT)); } - private static class TestResponderRSocket extends AbstractRSocket { + private static class TestResponderRSocket implements RSocket { AtomicInteger counter = new AtomicInteger(); diff --git a/rsocket-load-balancer/src/main/java/io/rsocket/client/LoadBalancedRSocketMono.java b/rsocket-load-balancer/src/main/java/io/rsocket/client/LoadBalancedRSocketMono.java index ed7550233..65ce80934 100644 --- a/rsocket-load-balancer/src/main/java/io/rsocket/client/LoadBalancedRSocketMono.java +++ b/rsocket-load-balancer/src/main/java/io/rsocket/client/LoadBalancedRSocketMono.java @@ -536,7 +536,7 @@ public Mono onClose() { * Wrapper of a RSocket, it computes statistics about the req/resp calls and update availability * accordingly. */ - private class WeightedSocket extends AbstractRSocket implements LoadBalancerSocketMetrics { + private class WeightedSocket implements LoadBalancerSocketMetrics, RSocket { private static final double STARTUP_PENALTY = Long.MAX_VALUE >> 12; private final Quantile lowerQuantile; @@ -554,6 +554,7 @@ private class WeightedSocket extends AbstractRSocket implements LoadBalancerSock private AtomicLong pendingStreams; // number of active streams private volatile double availability = 0.0; + private final MonoProcessor onClose = MonoProcessor.create(); WeightedSocket( RSocketSupplier factory, @@ -791,6 +792,21 @@ public double availability() { return availability; } + @Override + public void dispose() { + onClose.onComplete(); + } + + @Override + public boolean isDisposed() { + return onClose.isDisposed(); + } + + @Override + public Mono onClose() { + return onClose; + } + @Override public String toString() { return "WeightedSocket(" diff --git a/rsocket-test/src/main/java/io/rsocket/test/PingHandler.java b/rsocket-test/src/main/java/io/rsocket/test/PingHandler.java index 902014e7f..47f40a59d 100644 --- a/rsocket-test/src/main/java/io/rsocket/test/PingHandler.java +++ b/rsocket-test/src/main/java/io/rsocket/test/PingHandler.java @@ -16,7 +16,6 @@ package io.rsocket.test; -import io.rsocket.AbstractRSocket; import io.rsocket.ConnectionSetupPayload; import io.rsocket.Payload; import io.rsocket.RSocket; @@ -43,7 +42,7 @@ public PingHandler(byte[] data) { @Override public Mono accept(ConnectionSetupPayload setup, RSocket sendingSocket) { return Mono.just( - new AbstractRSocket() { + new RSocket() { @Override public Mono requestResponse(Payload payload) { payload.release(); diff --git a/rsocket-test/src/main/java/io/rsocket/test/TestRSocket.java b/rsocket-test/src/main/java/io/rsocket/test/TestRSocket.java index 26163d3a6..d48700445 100644 --- a/rsocket-test/src/main/java/io/rsocket/test/TestRSocket.java +++ b/rsocket-test/src/main/java/io/rsocket/test/TestRSocket.java @@ -16,14 +16,14 @@ package io.rsocket.test; -import io.rsocket.AbstractRSocket; import io.rsocket.Payload; +import io.rsocket.RSocket; import io.rsocket.util.DefaultPayload; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -public class TestRSocket extends AbstractRSocket { +public class TestRSocket implements RSocket { private final String data; private final String metadata; diff --git a/rsocket-transport-netty/src/test/java/io/rsocket/integration/FragmentTest.java b/rsocket-transport-netty/src/test/java/io/rsocket/integration/FragmentTest.java index 0ea938af2..23041ec65 100644 --- a/rsocket-transport-netty/src/test/java/io/rsocket/integration/FragmentTest.java +++ b/rsocket-transport-netty/src/test/java/io/rsocket/integration/FragmentTest.java @@ -18,7 +18,6 @@ import static org.assertj.core.api.Assertions.assertThat; -import io.rsocket.AbstractRSocket; import io.rsocket.Payload; import io.rsocket.RSocket; import io.rsocket.core.RSocketConnector; @@ -38,7 +37,7 @@ import reactor.core.publisher.Mono; public class FragmentTest { - private AbstractRSocket handler; + private RSocket handler; private CloseableChannel server; private String message = null; private String metaData = null; @@ -89,7 +88,7 @@ void testFragmentNoMetaData(int clientFrameSize, int serverFrameSize) { System.out.println( "-------------------------------------------------testFragmentNoMetaData-------------------------------------------------"); handler = - new AbstractRSocket() { + new RSocket() { @Override public Flux requestStream(Payload payload) { String request = payload.getDataUtf8(); @@ -119,7 +118,7 @@ void testFragmentRequestMetaDataOnly(int clientFrameSize, int serverFrameSize) { System.out.println( "-------------------------------------------------testFragmentRequestMetaDataOnly-------------------------------------------------"); handler = - new AbstractRSocket() { + new RSocket() { @Override public Flux requestStream(Payload payload) { String request = payload.getDataUtf8(); @@ -150,7 +149,7 @@ void testFragmentBothMetaData(int clientFrameSize, int serverFrameSize) { System.out.println( "-------------------------------------------------testFragmentBothMetaData-------------------------------------------------"); handler = - new AbstractRSocket() { + new RSocket() { @Override public Flux requestStream(Payload payload) { String request = payload.getDataUtf8(); diff --git a/rsocket-transport-netty/src/test/java/io/rsocket/transport/netty/WebSocketTransportIntegrationTest.java b/rsocket-transport-netty/src/test/java/io/rsocket/transport/netty/WebSocketTransportIntegrationTest.java index 7028a3846..c418dea0f 100644 --- a/rsocket-transport-netty/src/test/java/io/rsocket/transport/netty/WebSocketTransportIntegrationTest.java +++ b/rsocket-transport-netty/src/test/java/io/rsocket/transport/netty/WebSocketTransportIntegrationTest.java @@ -1,8 +1,7 @@ package io.rsocket.transport.netty; -import io.rsocket.AbstractRSocket; -import io.rsocket.Payload; import io.rsocket.RSocket; +import io.rsocket.SocketAcceptor; import io.rsocket.core.RSocketConnector; import io.rsocket.core.RSocketServer; import io.rsocket.transport.ServerTransport; @@ -14,7 +13,6 @@ import java.time.Duration; import org.junit.jupiter.api.Test; import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; import reactor.netty.DisposableServer; import reactor.netty.http.server.HttpServer; import reactor.test.StepVerifier; @@ -25,16 +23,9 @@ public class WebSocketTransportIntegrationTest { public void sendStreamOfDataWithExternalHttpServerTest() { ServerTransport.ConnectionAcceptor acceptor = RSocketServer.create( - (setupPayload, sendingRSocket) -> { - return Mono.just( - new AbstractRSocket() { - @Override - public Flux requestStream(Payload payload) { - return Flux.range(0, 10) - .map(i -> DefaultPayload.create(String.valueOf(i))); - } - }); - }) + SocketAcceptor.forRequestStream( + payload -> + Flux.range(0, 10).map(i -> DefaultPayload.create(String.valueOf(i))))) .asConnectionAcceptor(); DisposableServer server = diff --git a/rsocket-transport-netty/src/test/java/io/rsocket/transport/netty/WebsocketPingPongIntegrationTest.java b/rsocket-transport-netty/src/test/java/io/rsocket/transport/netty/WebsocketPingPongIntegrationTest.java index ab6c343de..e2ee9e521 100644 --- a/rsocket-transport-netty/src/test/java/io/rsocket/transport/netty/WebsocketPingPongIntegrationTest.java +++ b/rsocket-transport-netty/src/test/java/io/rsocket/transport/netty/WebsocketPingPongIntegrationTest.java @@ -8,10 +8,9 @@ import io.netty.handler.codec.http.websocketx.PongWebSocketFrame; import io.netty.handler.codec.http.websocketx.WebSocketFrame; import io.netty.util.ReferenceCountUtil; -import io.rsocket.AbstractRSocket; import io.rsocket.Closeable; -import io.rsocket.Payload; import io.rsocket.RSocket; +import io.rsocket.SocketAcceptor; import io.rsocket.core.RSocketConnector; import io.rsocket.core.RSocketServer; import io.rsocket.transport.ServerTransport; @@ -47,7 +46,7 @@ void tearDown() { @MethodSource("provideServerTransport") void webSocketPingPong(ServerTransport serverTransport) { server = - RSocketServer.create((setup, sendingSocket) -> Mono.just(new EchoRSocket())) + RSocketServer.create(SocketAcceptor.forRequestResponse(Mono::just)) .bind(serverTransport) .block(); @@ -100,13 +99,6 @@ private static Stream provideServerTransport() { HttpServer.create().host(host).port(port), routes -> {}, "/"))); } - private static class EchoRSocket extends AbstractRSocket { - @Override - public Mono requestResponse(Payload payload) { - return Mono.just(payload); - } - } - private static class PingSender extends ChannelInboundHandlerAdapter { private final MonoProcessor channel = MonoProcessor.create(); private final MonoProcessor pong = MonoProcessor.create(); From 31880691d2e582d13f39a576c2b473f95a975b66 Mon Sep 17 00:00:00 2001 From: Oleh Dokuka Date: Thu, 30 Apr 2020 16:09:49 +0300 Subject: [PATCH 07/25] reduces maintenance complexity (#806) --- .../io/rsocket/core/RSocketRequester.java | 216 +- .../java/io/rsocket/internal/BitUtil.java | 287 --- .../io/rsocket/internal/CollectionUtil.java | 121 -- .../java/io/rsocket/internal/Hashing.java | 124 -- .../internal/LimitableRequestPublisher.java | 204 -- .../rsocket/internal/SwitchTransformFlux.java | 581 ------ .../io/rsocket/internal/UnicastMonoEmpty.java | 84 - .../internal/UnicastMonoProcessor.java | 509 ----- .../java/io/rsocket/util/DisposableUtils.java | 45 - .../rsocket/util/DuplexConnectionProxy.java | 71 - .../main/java/io/rsocket/util/Function3.java | 22 - .../io/rsocket/util/MonoLifecycleHandler.java | 21 - .../rsocket/util/MultiSubscriberRSocket.java | 54 - .../java/io/rsocket/util/OnceConsumer.java | 33 - .../java/io/rsocket/util/RecyclerFactory.java | 46 - .../core/RSocketRequesterSubscribersTest.java | 18 - .../io/rsocket/core/RSocketRequesterTest.java | 18 - .../LimitableRequestPublisherTest.java | 33 - .../internal/SwitchTransformFluxTest.java | 446 ----- .../internal/UnicastMonoEmptyTest.java | 97 - .../internal/UnicastMonoProcessorTest.java | 1780 ----------------- 21 files changed, 122 insertions(+), 4688 deletions(-) delete mode 100644 rsocket-core/src/main/java/io/rsocket/internal/BitUtil.java delete mode 100644 rsocket-core/src/main/java/io/rsocket/internal/CollectionUtil.java delete mode 100644 rsocket-core/src/main/java/io/rsocket/internal/Hashing.java delete mode 100755 rsocket-core/src/main/java/io/rsocket/internal/LimitableRequestPublisher.java delete mode 100644 rsocket-core/src/main/java/io/rsocket/internal/SwitchTransformFlux.java delete mode 100644 rsocket-core/src/main/java/io/rsocket/internal/UnicastMonoEmpty.java delete mode 100644 rsocket-core/src/main/java/io/rsocket/internal/UnicastMonoProcessor.java delete mode 100644 rsocket-core/src/main/java/io/rsocket/util/DisposableUtils.java delete mode 100644 rsocket-core/src/main/java/io/rsocket/util/DuplexConnectionProxy.java delete mode 100644 rsocket-core/src/main/java/io/rsocket/util/Function3.java delete mode 100644 rsocket-core/src/main/java/io/rsocket/util/MonoLifecycleHandler.java delete mode 100644 rsocket-core/src/main/java/io/rsocket/util/MultiSubscriberRSocket.java delete mode 100644 rsocket-core/src/main/java/io/rsocket/util/OnceConsumer.java delete mode 100644 rsocket-core/src/main/java/io/rsocket/util/RecyclerFactory.java delete mode 100644 rsocket-core/src/test/java/io/rsocket/internal/LimitableRequestPublisherTest.java delete mode 100644 rsocket-core/src/test/java/io/rsocket/internal/SwitchTransformFluxTest.java delete mode 100644 rsocket-core/src/test/java/io/rsocket/internal/UnicastMonoEmptyTest.java delete mode 100644 rsocket-core/src/test/java/io/rsocket/internal/UnicastMonoProcessorTest.java diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java index fefb06003..f762bfe99 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java @@ -45,21 +45,18 @@ import io.rsocket.frame.decoder.PayloadDecoder; import io.rsocket.internal.SynchronizedIntObjectHashMap; import io.rsocket.internal.UnboundedProcessor; -import io.rsocket.internal.UnicastMonoEmpty; -import io.rsocket.internal.UnicastMonoProcessor; import io.rsocket.keepalive.KeepAliveFramesAcceptor; import io.rsocket.keepalive.KeepAliveHandler; import io.rsocket.keepalive.KeepAliveSupport; import io.rsocket.lease.RequesterLeaseHandler; -import io.rsocket.util.MonoLifecycleHandler; import java.nio.channels.ClosedChannelException; import java.util.concurrent.CancellationException; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import java.util.function.Consumer; import java.util.function.LongConsumer; import java.util.function.Supplier; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.reactivestreams.Processor; import org.reactivestreams.Publisher; @@ -210,15 +207,25 @@ private Mono handleFireAndForget(Payload payload) { return Mono.error(new IllegalArgumentException(INVALID_PAYLOAD_ERROR_MESSAGE)); } + final AtomicBoolean once = new AtomicBoolean(); final int streamId = streamIdSupplier.nextStreamId(receivers); - return UnicastMonoEmpty.newInstance( + return Mono.defer( () -> { - ByteBuf requestFrame = - RequestFireAndForgetFrameFlyweight.encodeReleasingPayload( - allocator, streamId, payload); + if (once.getAndSet(true)) { + return Mono.error( + new IllegalStateException("FireAndForgetMono allows only a single subscriber")); + } + + return Mono.empty() + .doOnSubscribe( + (__) -> { + ByteBuf requestFrame = + RequestFireAndForgetFrameFlyweight.encodeReleasingPayload( + allocator, streamId, payload); - sendProcessor.onNext(requestFrame); + sendProcessor.onNext(requestFrame); + }); }); } @@ -236,34 +243,37 @@ private Mono handleRequestResponse(final Payload payload) { int streamId = streamIdSupplier.nextStreamId(receivers); final UnboundedProcessor sendProcessor = this.sendProcessor; - - UnicastMonoProcessor receiver = - UnicastMonoProcessor.create( - new MonoLifecycleHandler() { - @Override - public void doOnSubscribe() { - final ByteBuf requestFrame = - RequestResponseFrameFlyweight.encodeReleasingPayload( - allocator, streamId, payload); - - sendProcessor.onNext(requestFrame); - } - - @Override - public void doOnTerminal( - @Nonnull SignalType signalType, - @Nullable Payload element, - @Nullable Throwable e) { - if (signalType == SignalType.CANCEL) { - sendProcessor.onNext(CancelFrameFlyweight.encode(allocator, streamId)); - } - removeStreamReceiver(streamId); - } - }); + final UnicastProcessor receiver = UnicastProcessor.create(Queues.one().get()); + final AtomicBoolean once = new AtomicBoolean(); receivers.put(streamId, receiver); - return receiver.doOnDiscard(ReferenceCounted.class, DROPPED_ELEMENTS_CONSUMER); + return Mono.defer( + () -> { + if (once.getAndSet(true)) { + return Mono.error( + new IllegalStateException("RequestResponseMono allows only a single subscriber")); + } + + return receiver + .next() + .doOnSubscribe( + (__) -> { + ByteBuf requestFrame = + RequestResponseFrameFlyweight.encodeReleasingPayload( + allocator, streamId, payload); + + sendProcessor.onNext(requestFrame); + }) + .doFinally( + signalType -> { + if (signalType == SignalType.CANCEL) { + sendProcessor.onNext(CancelFrameFlyweight.encode(allocator, streamId)); + } + removeStreamReceiver(streamId); + }) + .doOnDiscard(ReferenceCounted.class, DROPPED_ELEMENTS_CONSUMER); + }); } private Flux handleRequestStream(final Payload payload) { @@ -283,65 +293,76 @@ private Flux handleRequestStream(final Payload payload) { final UnboundedProcessor sendProcessor = this.sendProcessor; final UnicastProcessor receiver = UnicastProcessor.create(); final AtomicInteger wip = new AtomicInteger(0); + final AtomicBoolean once = new AtomicBoolean(); receivers.put(streamId, receiver); - return receiver - .doOnRequest( - new LongConsumer() { - - boolean firstRequest = true; + return Flux.defer( + () -> { + if (once.getAndSet(true)) { + return Flux.error( + new IllegalStateException("RequestStreamFlux allows only a single subscriber")); + } - @Override - public void accept(long n) { - if (firstRequest) { - firstRequest = false; - if (wip.getAndIncrement() != 0) { - // no need to do anything. - // stream was canceled and fist payload has already been discarded - return; - } - int missed = 1; - boolean firstHasBeenSent = false; - for (; ; ) { - if (!firstHasBeenSent) { - sendProcessor.onNext( - RequestStreamFrameFlyweight.encodeReleasingPayload( - allocator, streamId, n, payload)); - firstHasBeenSent = true; - } else { - // if first frame was sent but we cycling again, it means that wip was - // incremented at doOnCancel - sendProcessor.onNext(CancelFrameFlyweight.encode(allocator, streamId)); - return; + return receiver + .doOnRequest( + new LongConsumer() { + + boolean firstRequest = true; + + @Override + public void accept(long n) { + if (firstRequest) { + firstRequest = false; + if (wip.getAndIncrement() != 0) { + // no need to do anything. + // stream was canceled and fist payload has already been discarded + return; + } + int missed = 1; + boolean firstHasBeenSent = false; + for (; ; ) { + if (!firstHasBeenSent) { + sendProcessor.onNext( + RequestStreamFrameFlyweight.encodeReleasingPayload( + allocator, streamId, n, payload)); + firstHasBeenSent = true; + } else { + // if first frame was sent but we cycling again, it means that wip was + // incremented at doOnCancel + sendProcessor.onNext(CancelFrameFlyweight.encode(allocator, streamId)); + return; + } + + missed = wip.addAndGet(-missed); + if (missed == 0) { + return; + } + } + } else if (!receiver.isDisposed()) { + sendProcessor.onNext(RequestNFrameFlyweight.encode(allocator, streamId, n)); + } } + }) + .doFinally( + s -> { + if (s == SignalType.CANCEL) { + if (wip.getAndIncrement() != 0) { + return; + } - missed = wip.addAndGet(-missed); - if (missed == 0) { - return; + // check if we need to release payload + // only applicable if the cancel appears earlier than actual request + if (payload.refCnt() > 0) { + payload.release(); + } else { + sendProcessor.onNext(CancelFrameFlyweight.encode(allocator, streamId)); + } } - } - } else if (!receiver.isDisposed()) { - sendProcessor.onNext(RequestNFrameFlyweight.encode(allocator, streamId, n)); - } - } - }) - .doOnCancel( - () -> { - if (wip.getAndIncrement() != 0) { - return; - } - - // check if we need to release payload - // only applicable if the cancel appears earlier than actual request - if (payload.refCnt() > 0) { - payload.release(); - } else { - sendProcessor.onNext(CancelFrameFlyweight.encode(allocator, streamId)); - } - }) - .doFinally(s -> removeStreamReceiver(streamId)) - .doOnDiscard(ReferenceCounted.class, DROPPED_ELEMENTS_CONSUMER); + removeStreamReceiver(streamId); + }) + .doOnDiscard(ReferenceCounted.class, DROPPED_ELEMENTS_CONSUMER); + }); } private Flux handleChannel(Flux request) { @@ -522,12 +543,23 @@ private Mono handleMetadataPush(Payload payload) { return Mono.error(new IllegalArgumentException(INVALID_PAYLOAD_ERROR_MESSAGE)); } - return UnicastMonoEmpty.newInstance( + final AtomicBoolean once = new AtomicBoolean(); + + return Mono.defer( () -> { - ByteBuf metadataPushFrame = - MetadataPushFrameFlyweight.encodeReleasingPayload(allocator, payload); + if (once.getAndSet(true)) { + return Mono.error( + new IllegalStateException("MetadataPushMono allows only a single subscriber")); + } + + return Mono.empty() + .doOnSubscribe( + (__) -> { + ByteBuf metadataPushFrame = + MetadataPushFrameFlyweight.encodeReleasingPayload(allocator, payload); - sendProcessor.onNextPrioritized(metadataPushFrame); + sendProcessor.onNextPrioritized(metadataPushFrame); + }); }); } @@ -544,10 +576,6 @@ private Throwable checkAvailable() { return null; } - private boolean contains(int streamId) { - return receivers.containsKey(streamId); - } - private void handleIncomingFrames(ByteBuf frame) { try { int streamId = FrameHeaderFlyweight.streamId(frame); diff --git a/rsocket-core/src/main/java/io/rsocket/internal/BitUtil.java b/rsocket-core/src/main/java/io/rsocket/internal/BitUtil.java deleted file mode 100644 index 79be9ccd5..000000000 --- a/rsocket-core/src/main/java/io/rsocket/internal/BitUtil.java +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright 2014-2019 Real Logic Ltd. - * - * Licensed 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 io.rsocket.internal; - -import static java.nio.charset.StandardCharsets.UTF_8; - -import java.util.concurrent.ThreadLocalRandom; - -/** Miscellaneous useful functions for dealing with low level bits and bytes. */ -public class BitUtil { - /** Size of a byte in bytes */ - public static final int SIZE_OF_BYTE = 1; - - /** Size of a boolean in bytes */ - public static final int SIZE_OF_BOOLEAN = 1; - - /** Size of a char in bytes */ - public static final int SIZE_OF_CHAR = 2; - - /** Size of a short in bytes */ - public static final int SIZE_OF_SHORT = 2; - - /** Size of an int in bytes */ - public static final int SIZE_OF_INT = 4; - - /** Size of a float in bytes */ - public static final int SIZE_OF_FLOAT = 4; - - /** Size of a long in bytes */ - public static final int SIZE_OF_LONG = 8; - - /** Size of a double in bytes */ - public static final int SIZE_OF_DOUBLE = 8; - - /** Length of the data blocks used by the CPU cache sub-system in bytes. */ - public static final int CACHE_LINE_LENGTH = 64; - - private static final byte[] HEX_DIGIT_TABLE = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' - }; - - private static final byte[] FROM_HEX_DIGIT_TABLE; - - static { - FROM_HEX_DIGIT_TABLE = new byte[128]; - - FROM_HEX_DIGIT_TABLE['0'] = 0x00; - FROM_HEX_DIGIT_TABLE['1'] = 0x01; - FROM_HEX_DIGIT_TABLE['2'] = 0x02; - FROM_HEX_DIGIT_TABLE['3'] = 0x03; - FROM_HEX_DIGIT_TABLE['4'] = 0x04; - FROM_HEX_DIGIT_TABLE['5'] = 0x05; - FROM_HEX_DIGIT_TABLE['6'] = 0x06; - FROM_HEX_DIGIT_TABLE['7'] = 0x07; - FROM_HEX_DIGIT_TABLE['8'] = 0x08; - FROM_HEX_DIGIT_TABLE['9'] = 0x09; - FROM_HEX_DIGIT_TABLE['a'] = 0x0a; - FROM_HEX_DIGIT_TABLE['A'] = 0x0a; - FROM_HEX_DIGIT_TABLE['b'] = 0x0b; - FROM_HEX_DIGIT_TABLE['B'] = 0x0b; - FROM_HEX_DIGIT_TABLE['c'] = 0x0c; - FROM_HEX_DIGIT_TABLE['C'] = 0x0c; - FROM_HEX_DIGIT_TABLE['d'] = 0x0d; - FROM_HEX_DIGIT_TABLE['D'] = 0x0d; - FROM_HEX_DIGIT_TABLE['e'] = 0x0e; - FROM_HEX_DIGIT_TABLE['E'] = 0x0e; - FROM_HEX_DIGIT_TABLE['f'] = 0x0f; - FROM_HEX_DIGIT_TABLE['F'] = 0x0f; - } - - private static final int LAST_DIGIT_MASK = 0b1; - - /** - * Fast method of finding the next power of 2 greater than or equal to the supplied value. - * - *

If the value is <= 0 then 1 will be returned. - * - *

This method is not suitable for {@link Integer#MIN_VALUE} or numbers greater than 2^30. - * - * @param value from which to search for next power of 2 - * @return The next power of 2 or the value itself if it is a power of 2 - */ - public static int findNextPositivePowerOfTwo(final int value) { - return 1 << (Integer.SIZE - Integer.numberOfLeadingZeros(value - 1)); - } - - /** - * Align a value to the next multiple up of alignment. If the value equals an alignment multiple - * then it is returned unchanged. - * - *

This method executes without branching. This code is designed to be use in the fast path and - * should not be used with negative numbers. Negative numbers will result in undefined behaviour. - * - * @param value to be aligned up. - * @param alignment to be used. - * @return the value aligned to the next boundary. - */ - public static int align(final int value, final int alignment) { - return (value + (alignment - 1)) & -alignment; - } - - /** - * Generate a byte array from the hex representation of the given byte array. - * - * @param buffer to convert from a hex representation (in Big Endian). - * @return new byte array that is decimal representation of the passed array. - */ - public static byte[] fromHexByteArray(final byte[] buffer) { - final byte[] outputBuffer = new byte[buffer.length >> 1]; - - for (int i = 0; i < buffer.length; i += 2) { - final int hi = FROM_HEX_DIGIT_TABLE[buffer[i]] << 4; - final int lo = FROM_HEX_DIGIT_TABLE[buffer[i + 1]]; // lgtm [java/index-out-of-bounds] - outputBuffer[i >> 1] = (byte) (hi | lo); - } - - return outputBuffer; - } - - /** - * Generate a byte array that is a hex representation of a given byte array. - * - * @param buffer to convert to a hex representation. - * @return new byte array that is hex representation (in Big Endian) of the passed array. - */ - public static byte[] toHexByteArray(final byte[] buffer) { - return toHexByteArray(buffer, 0, buffer.length); - } - - /** - * Generate a byte array that is a hex representation of a given byte array. - * - * @param buffer to convert to a hex representation. - * @param offset the offset into the buffer. - * @param length the number of bytes to convert. - * @return new byte array that is hex representation (in Big Endian) of the passed array. - */ - public static byte[] toHexByteArray(final byte[] buffer, final int offset, final int length) { - final byte[] outputBuffer = new byte[length << 1]; - - for (int i = 0; i < (length << 1); i += 2) { - final byte b = buffer[offset + (i >> 1)]; - - outputBuffer[i] = HEX_DIGIT_TABLE[(b >> 4) & 0x0F]; - outputBuffer[i + 1] = HEX_DIGIT_TABLE[b & 0x0F]; - } - - return outputBuffer; - } - - /** - * Generate a byte array from a string that is the hex representation of the given byte array. - * - * @param string to convert from a hex representation (in Big Endian). - * @return new byte array holding the decimal representation of the passed array. - */ - public static byte[] fromHex(final String string) { - return fromHexByteArray(string.getBytes(UTF_8)); - } - - /** - * Generate a string that is the hex representation of a given byte array. - * - * @param buffer to convert to a hex representation. - * @param offset the offset into the buffer. - * @param length the number of bytes to convert. - * @return new String holding the hex representation (in Big Endian) of the passed array. - */ - public static String toHex(final byte[] buffer, final int offset, final int length) { - return new String(toHexByteArray(buffer, offset, length), UTF_8); - } - - /** - * Generate a string that is the hex representation of a given byte array. - * - * @param buffer to convert to a hex representation. - * @return new String holding the hex representation (in Big Endian) of the passed array. - */ - public static String toHex(final byte[] buffer) { - return new String(toHexByteArray(buffer), UTF_8); - } - - /** - * Is a number even. - * - * @param value to check. - * @return true if the number is even otherwise false. - */ - public static boolean isEven(final int value) { - return (value & LAST_DIGIT_MASK) == 0; - } - - /** - * Is a value a positive power of 2. - * - * @param value to be checked. - * @return true if the number is a positive power of 2, otherwise false. - */ - public static boolean isPowerOfTwo(final int value) { - return value > 0 && ((value & (~value + 1)) == value); - } - - /** - * Cycles indices of an array one at a time in a forward fashion - * - * @param current value to be incremented. - * @param max value for the cycle. - * @return the next value, or zero if max is reached. - */ - public static int next(final int current, final int max) { - int next = current + 1; - if (next == max) { - next = 0; - } - - return next; - } - - /** - * Cycles indices of an array one at a time in a backwards fashion - * - * @param current value to be decremented. - * @param max value of the cycle. - * @return the next value, or max - 1 if current is zero. - */ - public static int previous(final int current, final int max) { - if (0 == current) { - return max - 1; - } - - return current - 1; - } - - /** - * Calculate the shift value to scale a number based on how refs are compressed or not. - * - * @param scale of the number reported by Unsafe. - * @return how many times the number needs to be shifted to the left. - */ - public static int calculateShiftForScale(final int scale) { - if (4 == scale) { - return 2; - } else if (8 == scale) { - return 3; - } - - throw new IllegalArgumentException("unknown pointer size for scale=" + scale); - } - - /** - * Generate a randomised integer over [{@link Integer#MIN_VALUE}, {@link Integer#MAX_VALUE}]. - * - * @return randomised integer suitable as an Id. - */ - public static int generateRandomisedId() { - return ThreadLocalRandom.current().nextInt(); - } - - /** - * Is an address aligned on a boundary. - * - * @param address to be tested. - * @param alignment boundary the address is tested against. - * @return true if the address is on the aligned boundary otherwise false. - * @throws IllegalArgumentException if the alignment is not a power of 2. - */ - public static boolean isAligned(final long address, final int alignment) { - if (!BitUtil.isPowerOfTwo(alignment)) { - throw new IllegalArgumentException("alignment must be a power of 2: alignment=" + alignment); - } - - return (address & (alignment - 1)) == 0; - } -} diff --git a/rsocket-core/src/main/java/io/rsocket/internal/CollectionUtil.java b/rsocket-core/src/main/java/io/rsocket/internal/CollectionUtil.java deleted file mode 100644 index 8d4526c36..000000000 --- a/rsocket-core/src/main/java/io/rsocket/internal/CollectionUtil.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2014-2019 Real Logic Ltd. - * - * Licensed 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 io.rsocket.internal; - -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.function.ToIntFunction; - -/** Utility functions for collection objects. */ -public class CollectionUtil { - /** - * A getOrDefault that doesn't create garbage if its suppler is non-capturing. - * - * @param map to perform the lookup on. - * @param key on which the lookup is done. - * @param supplier of the default value if one is not found. - * @param type of the key - * @param type of the value - * @return the value if found or a new default which as been added to the map. - */ - public static V getOrDefault( - final Map map, final K key, final Function supplier) { - V value = map.get(key); - if (value == null) { - value = supplier.apply(key); - map.put(key, value); - } - - return value; - } - - /** - * Garbage free sum function. - * - *

Note: the list must implement {@link java.util.RandomAccess} to be efficient. - * - * @param values the list of input values - * @param function function that map each value to an int - * @param the value to add up - * @return the sum of all the int values returned for each member of the list. - */ - public static int sum(final List values, final ToIntFunction function) { - int total = 0; - - final int size = values.size(); - for (int i = 0; i < size; i++) { - final V value = values.get(i); - total += function.applyAsInt(value); - } - - return total; - } - - /** - * Validate that a load factor is in the range of 0.1 to 0.9. - * - *

Load factors in the range 0.5 - 0.7 are recommended for open-addressing with linear probing. - * - * @param loadFactor to be validated. - */ - public static void validateLoadFactor(final float loadFactor) { - if (loadFactor < 0.1f || loadFactor > 0.9f) { - throw new IllegalArgumentException( - "load factor must be in the range of 0.1 to 0.9: " + loadFactor); - } - } - - /** - * Validate that a number is a power of two. - * - * @param value to be validated. - */ - public static void validatePositivePowerOfTwo(final int value) { - if (value > 0 && 1 == (value & (value - 1))) { - throw new IllegalStateException("value must be a positive power of two"); - } - } - - /** - * Remove element from a list if it matches a predicate. - * - *

Note: the list must implement {@link java.util.RandomAccess} to be efficient. - * - * @param values to be iterated over. - * @param predicate to test the value against - * @param type of the value. - * @return the number of items remove. - */ - public static int removeIf(final List values, final Predicate predicate) { - int size = values.size(); - int total = 0; - - for (int i = 0; i < size; ) { - final T value = values.get(i); - if (predicate.test(value)) { - values.remove(i); - total++; - size--; - } else { - i++; - } - } - - return total; - } -} diff --git a/rsocket-core/src/main/java/io/rsocket/internal/Hashing.java b/rsocket-core/src/main/java/io/rsocket/internal/Hashing.java deleted file mode 100644 index 613dce209..000000000 --- a/rsocket-core/src/main/java/io/rsocket/internal/Hashing.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2014-2019 Real Logic Ltd. - * - * Licensed 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 io.rsocket.internal; - -/** Hashing functions for applying to integers. */ -public class Hashing { - /** Default load factor to be used in open addressing hashed data structures. */ - public static final float DEFAULT_LOAD_FACTOR = 0.55f; - - /** - * Generate a hash for an int value. This is a no op. - * - * @param value to be hashed. - * @return the hashed value. - */ - public static int hash(final int value) { - return value * 31; - } - - /** - * Generate a hash for an long value. - * - * @param value to be hashed. - * @return the hashed value. - */ - public static int hash(final long value) { - long hash = value * 31; - hash = (int) hash ^ (int) (hash >>> 32); - - return (int) hash; - } - - /** - * Generate a hash for a int value. - * - * @param value to be hashed. - * @param mask mask to be applied that must be a power of 2 - 1. - * @return the hash of the value. - */ - public static int hash(final int value, final int mask) { - final int hash = value * 31; - - return hash & mask; - } - - /** - * Generate a hash for a K value. - * - * @param is the type of value - * @param value to be hashed. - * @param mask mask to be applied that must be a power of 2 - 1. - * @return the hash of the value. - */ - public static int hash(final K value, final int mask) { - final int hash = value.hashCode(); - - return hash & mask; - } - - /** - * Generate a hash for a long value. - * - * @param value to be hashed. - * @param mask mask to be applied that must be a power of 2 - 1. - * @return the hash of the value. - */ - public static int hash(final long value, final int mask) { - long hash = value * 31; - hash = (int) hash ^ (int) (hash >>> 32); - - return (int) hash & mask; - } - - /** - * Generate an even hash for a int value. - * - * @param value to be hashed. - * @param mask mask to be applied that must be a power of 2 - 1. - * @return the hash of the value which is always even. - */ - public static int evenHash(final int value, final int mask) { - final int hash = (value << 1) - (value << 8); - - return hash & mask; - } - - /** - * Generate an even hash for a long value. - * - * @param value to be hashed. - * @param mask mask to be applied that must be a power of 2 - 1. - * @return the hash of the value which is always even. - */ - public static int evenHash(final long value, final int mask) { - int hash = (int) value ^ (int) (value >>> 32); - hash = (hash << 1) - (hash << 8); - - return hash & mask; - } - - /** - * Combined two 32 bit keys into a 64-bit compound. - * - * @param keyPartA to make the upper bits - * @param keyPartB to make the lower bits. - * @return the compound key - */ - public static long compoundKey(final int keyPartA, final int keyPartB) { - return ((long) keyPartA << 32) | (keyPartB & 0xFFFF_FFFFL); - } -} diff --git a/rsocket-core/src/main/java/io/rsocket/internal/LimitableRequestPublisher.java b/rsocket-core/src/main/java/io/rsocket/internal/LimitableRequestPublisher.java deleted file mode 100755 index 8adb7542a..000000000 --- a/rsocket-core/src/main/java/io/rsocket/internal/LimitableRequestPublisher.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright 2015-2018 the original author or authors. - * - * Licensed 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 io.rsocket.internal; - -import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; -import javax.annotation.Nullable; -import org.reactivestreams.Publisher; -import org.reactivestreams.Subscriber; -import org.reactivestreams.Subscription; -import reactor.core.CoreSubscriber; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Operators; - -/** */ -public class LimitableRequestPublisher extends Flux implements Subscription { - - private static final int NOT_CANCELED_STATE = 0; - private static final int CANCELED_STATE = 1; - - private final Publisher source; - - private volatile int canceled; - private static final AtomicIntegerFieldUpdater CANCELED = - AtomicIntegerFieldUpdater.newUpdater(LimitableRequestPublisher.class, "canceled"); - - private final long prefetch; - - private long internalRequested; - - private long externalRequested; - - private boolean subscribed; - - private @Nullable Subscription internalSubscription; - - private LimitableRequestPublisher(Publisher source, long prefetch) { - this.source = source; - this.prefetch = prefetch; - } - - public static LimitableRequestPublisher wrap(Publisher source, long prefetch) { - return new LimitableRequestPublisher<>(source, prefetch); - } - - public static LimitableRequestPublisher wrap(Publisher source) { - return wrap(source, Long.MAX_VALUE); - } - - @Override - public void subscribe(CoreSubscriber destination) { - synchronized (this) { - if (subscribed) { - throw new IllegalStateException("only one subscriber at a time"); - } - - subscribed = true; - } - final InnerOperator s = new InnerOperator(destination); - - destination.onSubscribe(s); - source.subscribe(s); - increaseInternalLimit(prefetch); - } - - public void increaseInternalLimit(long n) { - synchronized (this) { - long requested = internalRequested; - if (requested == Long.MAX_VALUE) { - return; - } - internalRequested = Operators.addCap(n, requested); - } - - requestN(); - } - - @Override - public void request(long n) { - synchronized (this) { - long requested = externalRequested; - if (requested == Long.MAX_VALUE) { - return; - } - externalRequested = Operators.addCap(n, requested); - } - - requestN(); - } - - private void requestN() { - long r; - final Subscription s; - - synchronized (this) { - s = internalSubscription; - if (s == null) { - return; - } - - long er = externalRequested; - long ir = internalRequested; - - if (er != Long.MAX_VALUE || ir != Long.MAX_VALUE) { - r = Math.min(ir, er); - if (er != Long.MAX_VALUE) { - externalRequested -= r; - } - if (ir != Long.MAX_VALUE) { - internalRequested -= r; - } - } else { - r = Long.MAX_VALUE; - } - } - - if (r > 0) { - s.request(r); - } - } - - public void cancel() { - if (!isCanceled() && CANCELED.compareAndSet(this, NOT_CANCELED_STATE, CANCELED_STATE)) { - Subscription s; - - synchronized (this) { - s = internalSubscription; - internalSubscription = null; - subscribed = false; - } - - if (s != null) { - s.cancel(); - } - } - } - - private boolean isCanceled() { - return canceled == 1; - } - - private class InnerOperator implements CoreSubscriber, Subscription { - final Subscriber destination; - - private InnerOperator(Subscriber destination) { - this.destination = destination; - } - - @Override - public void onSubscribe(Subscription s) { - synchronized (LimitableRequestPublisher.this) { - LimitableRequestPublisher.this.internalSubscription = s; - - if (isCanceled()) { - s.cancel(); - subscribed = false; - LimitableRequestPublisher.this.internalSubscription = null; - } - } - - requestN(); - } - - @Override - public void onNext(T t) { - try { - destination.onNext(t); - } catch (Throwable e) { - onError(e); - } - } - - @Override - public void onError(Throwable t) { - destination.onError(t); - } - - @Override - public void onComplete() { - destination.onComplete(); - } - - @Override - public void request(long n) {} - - @Override - public void cancel() { - LimitableRequestPublisher.this.cancel(); - } - } -} diff --git a/rsocket-core/src/main/java/io/rsocket/internal/SwitchTransformFlux.java b/rsocket-core/src/main/java/io/rsocket/internal/SwitchTransformFlux.java deleted file mode 100644 index 0d2e5988e..000000000 --- a/rsocket-core/src/main/java/io/rsocket/internal/SwitchTransformFlux.java +++ /dev/null @@ -1,581 +0,0 @@ -/* - * Copyright 2015-2018 the original author or authors. - * - * Licensed 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 io.rsocket.internal; - -import java.util.Objects; -import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; -import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; -import java.util.function.BiFunction; -import org.reactivestreams.Publisher; -import org.reactivestreams.Subscription; -import reactor.core.CoreSubscriber; -import reactor.core.Fuseable; -import reactor.core.Scannable; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Operators; -import reactor.util.annotation.Nullable; -import reactor.util.context.Context; - -/** @deprecated in favour of {@link Flux#switchOnFirst(BiFunction)} */ -@Deprecated -public final class SwitchTransformFlux extends Flux { - - final Publisher source; - final BiFunction, Publisher> transformer; - - public SwitchTransformFlux( - Publisher source, BiFunction, Publisher> transformer) { - this.source = Objects.requireNonNull(source, "source"); - this.transformer = Objects.requireNonNull(transformer, "transformer"); - } - - @Override - public int getPrefetch() { - return 1; - } - - @Override - @SuppressWarnings("unchecked") - public void subscribe(CoreSubscriber actual) { - if (actual instanceof Fuseable.ConditionalSubscriber) { - source.subscribe( - new SwitchTransformConditionalOperator<>( - (Fuseable.ConditionalSubscriber) actual, transformer)); - return; - } - source.subscribe(new SwitchTransformOperator<>(actual, transformer)); - } - - static final class SwitchTransformOperator extends Flux - implements CoreSubscriber, Subscription, Scannable { - - final CoreSubscriber outer; - final BiFunction, Publisher> transformer; - - Subscription s; - Throwable throwable; - - volatile boolean done; - volatile T first; - - volatile CoreSubscriber inner; - - @SuppressWarnings("rawtypes") - static final AtomicReferenceFieldUpdater INNER = - AtomicReferenceFieldUpdater.newUpdater( - SwitchTransformOperator.class, CoreSubscriber.class, "inner"); - - volatile int wip; - - @SuppressWarnings("rawtypes") - static final AtomicIntegerFieldUpdater WIP = - AtomicIntegerFieldUpdater.newUpdater(SwitchTransformOperator.class, "wip"); - - volatile int once; - - @SuppressWarnings("rawtypes") - static final AtomicIntegerFieldUpdater ONCE = - AtomicIntegerFieldUpdater.newUpdater(SwitchTransformOperator.class, "once"); - - SwitchTransformOperator( - CoreSubscriber outer, - BiFunction, Publisher> transformer) { - this.outer = outer; - this.transformer = transformer; - } - - @Override - @Nullable - public Object scanUnsafe(Attr key) { - if (key == Attr.CANCELLED) return s == Operators.cancelledSubscription(); - if (key == Attr.PREFETCH) return 1; - - return null; - } - - @Override - public Context currentContext() { - CoreSubscriber actual = inner; - - if (actual != null) { - return actual.currentContext(); - } - - return outer.currentContext(); - } - - @Override - public void cancel() { - if (s != Operators.cancelledSubscription()) { - Subscription s = this.s; - this.s = Operators.cancelledSubscription(); - - if (WIP.getAndIncrement(this) == 0) { - INNER.lazySet(this, null); - - T f = first; - if (f != null) { - first = null; - Operators.onDiscard(f, currentContext()); - } - } - - s.cancel(); - } - } - - @Override - public void subscribe(CoreSubscriber actual) { - if (once == 0 && ONCE.compareAndSet(this, 0, 1)) { - INNER.lazySet(this, actual); - actual.onSubscribe(this); - } else { - Operators.error( - actual, new IllegalStateException("SwitchTransform allows only one Subscriber")); - } - } - - @Override - public void onSubscribe(Subscription s) { - if (Operators.validate(this.s, s)) { - this.s = s; - s.request(1); - } - } - - @Override - public void onNext(T t) { - if (done) { - Operators.onNextDropped(t, currentContext()); - return; - } - - CoreSubscriber i = inner; - - if (i == null) { - try { - first = t; - Publisher result = - Objects.requireNonNull( - transformer.apply(t, this), "The transformer returned a null value"); - result.subscribe(outer); - return; - } catch (Throwable e) { - onError(Operators.onOperatorError(s, e, t, currentContext())); - return; - } - } - - i.onNext(t); - } - - @Override - public void onError(Throwable t) { - if (done) { - Operators.onErrorDropped(t, currentContext()); - return; - } - - throwable = t; - done = true; - CoreSubscriber i = inner; - - if (i != null) { - if (first == null) { - drainRegular(); - } - } else { - Operators.error(outer, t); - } - } - - @Override - public void onComplete() { - if (done) { - return; - } - - done = true; - CoreSubscriber i = inner; - - if (i != null) { - if (first == null) { - drainRegular(); - } - } else { - Operators.complete(outer); - } - } - - @Override - public void request(long n) { - if (Operators.validate(n)) { - if (first != null && drainRegular() && n != Long.MAX_VALUE) { - if (--n > 0) { - s.request(n); - } - } else { - s.request(n); - } - } - } - - boolean drainRegular() { - if (WIP.getAndIncrement(this) != 0) { - return false; - } - - T f = first; - int m = 1; - boolean sent = false; - Subscription s = this.s; - CoreSubscriber a = inner; - - for (; ; ) { - if (f != null) { - first = null; - - if (s == Operators.cancelledSubscription()) { - Operators.onDiscard(f, a.currentContext()); - return true; - } - - a.onNext(f); - f = null; - sent = true; - } - - if (s == Operators.cancelledSubscription()) { - return sent; - } - - if (done) { - Throwable t = throwable; - if (t != null) { - a.onError(t); - } else { - a.onComplete(); - } - return sent; - } - - m = WIP.addAndGet(this, -m); - - if (m == 0) { - return sent; - } - } - } - } - - static final class SwitchTransformConditionalOperator extends Flux - implements Fuseable.ConditionalSubscriber, Subscription, Scannable { - - final Fuseable.ConditionalSubscriber outer; - final BiFunction, Publisher> transformer; - - Subscription s; - Throwable throwable; - - volatile boolean done; - volatile T first; - - volatile Fuseable.ConditionalSubscriber inner; - - @SuppressWarnings("rawtypes") - static final AtomicReferenceFieldUpdater< - SwitchTransformConditionalOperator, Fuseable.ConditionalSubscriber> - INNER = - AtomicReferenceFieldUpdater.newUpdater( - SwitchTransformConditionalOperator.class, - Fuseable.ConditionalSubscriber.class, - "inner"); - - volatile int wip; - - @SuppressWarnings("rawtypes") - static final AtomicIntegerFieldUpdater WIP = - AtomicIntegerFieldUpdater.newUpdater(SwitchTransformConditionalOperator.class, "wip"); - - volatile int once; - - @SuppressWarnings("rawtypes") - static final AtomicIntegerFieldUpdater ONCE = - AtomicIntegerFieldUpdater.newUpdater(SwitchTransformConditionalOperator.class, "once"); - - SwitchTransformConditionalOperator( - Fuseable.ConditionalSubscriber outer, - BiFunction, Publisher> transformer) { - this.outer = outer; - this.transformer = transformer; - } - - @Override - @Nullable - public Object scanUnsafe(Attr key) { - if (key == Attr.CANCELLED) return s == Operators.cancelledSubscription(); - if (key == Attr.PREFETCH) return 1; - - return null; - } - - @Override - public Context currentContext() { - CoreSubscriber actual = inner; - - if (actual != null) { - return actual.currentContext(); - } - - return outer.currentContext(); - } - - @Override - public void cancel() { - if (s != Operators.cancelledSubscription()) { - Subscription s = this.s; - this.s = Operators.cancelledSubscription(); - - if (WIP.getAndIncrement(this) == 0) { - INNER.lazySet(this, null); - - T f = first; - if (f != null) { - first = null; - Operators.onDiscard(f, currentContext()); - } - } - - s.cancel(); - } - } - - @Override - @SuppressWarnings("unchecked") - public void subscribe(CoreSubscriber actual) { - if (once == 0 && ONCE.compareAndSet(this, 0, 1)) { - if (actual instanceof Fuseable.ConditionalSubscriber) { - INNER.lazySet(this, (Fuseable.ConditionalSubscriber) actual); - } else { - INNER.lazySet(this, new ConditionalSubscriberAdapter<>(actual)); - } - actual.onSubscribe(this); - } else { - Operators.error( - actual, new IllegalStateException("SwitchTransform allows only one Subscriber")); - } - } - - @Override - public void onSubscribe(Subscription s) { - if (Operators.validate(this.s, s)) { - this.s = s; - s.request(1); - } - } - - @Override - public void onNext(T t) { - if (done) { - Operators.onNextDropped(t, currentContext()); - return; - } - - CoreSubscriber i = inner; - - if (i == null) { - try { - first = t; - Publisher result = - Objects.requireNonNull( - transformer.apply(t, this), "The transformer returned a null value"); - result.subscribe(outer); - return; - } catch (Throwable e) { - onError(Operators.onOperatorError(s, e, t, currentContext())); - return; - } - } - - i.onNext(t); - } - - @Override - public boolean tryOnNext(T t) { - if (done) { - Operators.onNextDropped(t, currentContext()); - return false; - } - - Fuseable.ConditionalSubscriber i = inner; - - if (i == null) { - try { - first = t; - Publisher result = - Objects.requireNonNull( - transformer.apply(t, this), "The transformer returned a null value"); - result.subscribe(outer); - return true; - } catch (Throwable e) { - onError(Operators.onOperatorError(s, e, t, currentContext())); - return false; - } - } - - return i.tryOnNext(t); - } - - @Override - public void onError(Throwable t) { - if (done) { - Operators.onErrorDropped(t, currentContext()); - return; - } - - throwable = t; - done = true; - CoreSubscriber i = inner; - - if (i != null) { - if (first == null) { - drainRegular(); - } - } else { - Operators.error(outer, t); - } - } - - @Override - public void onComplete() { - if (done) { - return; - } - - done = true; - CoreSubscriber i = inner; - - if (i != null) { - if (first == null) { - drainRegular(); - } - } else { - Operators.complete(outer); - } - } - - @Override - public void request(long n) { - if (Operators.validate(n)) { - if (first != null && drainRegular() && n != Long.MAX_VALUE) { - if (--n > 0) { - s.request(n); - } - } else { - s.request(n); - } - } - } - - boolean drainRegular() { - if (WIP.getAndIncrement(this) != 0) { - return false; - } - - T f = first; - int m = 1; - boolean sent = false; - Subscription s = this.s; - CoreSubscriber a = inner; - - for (; ; ) { - if (f != null) { - first = null; - - if (s == Operators.cancelledSubscription()) { - Operators.onDiscard(f, a.currentContext()); - return true; - } - - a.onNext(f); - f = null; - sent = true; - } - - if (s == Operators.cancelledSubscription()) { - return sent; - } - - if (done) { - Throwable t = throwable; - if (t != null) { - a.onError(t); - } else { - a.onComplete(); - } - return sent; - } - - m = WIP.addAndGet(this, -m); - - if (m == 0) { - return sent; - } - } - } - } - - static final class ConditionalSubscriberAdapter implements Fuseable.ConditionalSubscriber { - - final CoreSubscriber delegate; - - ConditionalSubscriberAdapter(CoreSubscriber delegate) { - this.delegate = delegate; - } - - @Override - public Context currentContext() { - return delegate.currentContext(); - } - - @Override - public void onSubscribe(Subscription s) { - delegate.onSubscribe(s); - } - - @Override - public void onNext(T t) { - delegate.onNext(t); - } - - @Override - public void onError(Throwable t) { - delegate.onError(t); - } - - @Override - public void onComplete() { - delegate.onComplete(); - } - - @Override - public boolean tryOnNext(T t) { - delegate.onNext(t); - return true; - } - } -} diff --git a/rsocket-core/src/main/java/io/rsocket/internal/UnicastMonoEmpty.java b/rsocket-core/src/main/java/io/rsocket/internal/UnicastMonoEmpty.java deleted file mode 100644 index 64a7d4422..000000000 --- a/rsocket-core/src/main/java/io/rsocket/internal/UnicastMonoEmpty.java +++ /dev/null @@ -1,84 +0,0 @@ -package io.rsocket.internal; - -import java.time.Duration; -import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; -import reactor.core.CoreSubscriber; -import reactor.core.Scannable; -import reactor.core.publisher.Mono; -import reactor.core.publisher.Operators; -import reactor.util.annotation.Nullable; - -/** - * Represents an empty publisher which only calls onSubscribe and onComplete and allows only a - * single subscriber. - * - * @see Reactive-Streams-Commons - */ -public final class UnicastMonoEmpty extends Mono implements Scannable { - - final Runnable onSubscribe; - - volatile int once; - - @SuppressWarnings("rawtypes") - static final AtomicIntegerFieldUpdater ONCE = - AtomicIntegerFieldUpdater.newUpdater(UnicastMonoEmpty.class, "once"); - - UnicastMonoEmpty(Runnable onSubscribe) { - this.onSubscribe = onSubscribe; - } - - @Override - public void subscribe(CoreSubscriber actual) { - if (once == 0 && ONCE.compareAndSet(this, 0, 1)) { - onSubscribe.run(); - Operators.complete(actual); - } else { - Operators.error( - actual, new IllegalStateException("UnicastMonoEmpty allows only a single Subscriber")); - } - } - - /** - * Returns a properly parametrized instance of this empty Publisher. - * - * @param the output type - * @return a properly parametrized instance of this empty Publisher - */ - @SuppressWarnings("unchecked") - public static Mono newInstance(Runnable onSubscribe) { - return (Mono) new UnicastMonoEmpty(onSubscribe); - } - - @Override - @Nullable - public Object block(Duration m) { - if (once == 0 && ONCE.compareAndSet(this, 0, 1)) { - onSubscribe.run(); - return null; - } else { - throw new IllegalStateException("UnicastMonoEmpty allows only a single Subscriber"); - } - } - - @Override - @Nullable - public Object block() { - if (once == 0 && ONCE.compareAndSet(this, 0, 1)) { - onSubscribe.run(); - return null; - } else { - throw new IllegalStateException("UnicastMonoEmpty allows only a single Subscriber"); - } - } - - @Override - public Object scanUnsafe(Attr key) { - return null; // no particular key to be represented, still useful in hooks - } - - @Override - public String stepName() { - return "source(UnicastMonoEmpty)"; - } -} diff --git a/rsocket-core/src/main/java/io/rsocket/internal/UnicastMonoProcessor.java b/rsocket-core/src/main/java/io/rsocket/internal/UnicastMonoProcessor.java deleted file mode 100644 index c5b06e086..000000000 --- a/rsocket-core/src/main/java/io/rsocket/internal/UnicastMonoProcessor.java +++ /dev/null @@ -1,509 +0,0 @@ -/* - * Copyright 2015-2019 the original author or authors. - * - * Licensed 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 io.rsocket.internal; - -import io.rsocket.util.MonoLifecycleHandler; -import java.util.Objects; -import java.util.concurrent.CancellationException; -import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; -import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; -import org.reactivestreams.Processor; -import org.reactivestreams.Subscriber; -import org.reactivestreams.Subscription; -import reactor.core.CoreSubscriber; -import reactor.core.Disposable; -import reactor.core.Exceptions; -import reactor.core.Scannable; -import reactor.core.publisher.Mono; -import reactor.core.publisher.Operators; -import reactor.core.publisher.SignalType; -import reactor.util.annotation.NonNull; -import reactor.util.annotation.Nullable; -import reactor.util.context.Context; - -public class UnicastMonoProcessor extends Mono - implements Processor, CoreSubscriber, Disposable, Subscription, Scannable { - - static final MonoLifecycleHandler DEFAULT_LIFECYCLE = new MonoLifecycleHandler() {}; - - /** - * Create a {@link UnicastMonoProcessor} that will eagerly request 1 on {@link - * #onSubscribe(Subscription)}, cache and emit the eventual result for a single subscriber. - * - * @param type of the expected value - * @return A {@link UnicastMonoProcessor}. - */ - @SuppressWarnings("unchecked") - public static UnicastMonoProcessor create() { - return new UnicastMonoProcessor(DEFAULT_LIFECYCLE); - } - - /** - * Create a {@link UnicastMonoProcessor} that will eagerly request 1 on {@link - * #onSubscribe(Subscription)}, cache and emit the eventual result for a single subscriber. - * - * @param lifecycleHandler lifecycle handler - * @param type of the expected value - * @return A {@link UnicastMonoProcessor}. - */ - public static UnicastMonoProcessor create(MonoLifecycleHandler lifecycleHandler) { - return new UnicastMonoProcessor<>(lifecycleHandler); - } - - /** Indicates this Subscription has no value and not requested yet. */ - static final int NO_SUBSCRIBER_NO_RESULT = 0; - /** Indicates this Subscription has no value and not requested yet. */ - static final int NO_SUBSCRIBER_HAS_RESULT = 1; - /** Indicates this Subscription has no value and not requested yet. */ - static final int NO_REQUEST_NO_RESULT = 4; - /** Indicates this Subscription has a value but not requested yet. */ - static final int NO_REQUEST_HAS_RESULT = 5; - /** Indicates this Subscription has been requested but there is no value yet. */ - static final int HAS_REQUEST_NO_RESULT = 6; - /** Indicates this Subscription has both request and value. */ - static final int HAS_REQUEST_HAS_RESULT = 7; - /** Indicates the Subscription has been cancelled. */ - static final int CANCELLED = 8; - - volatile int state; - - @SuppressWarnings("rawtypes") - static final AtomicIntegerFieldUpdater STATE = - AtomicIntegerFieldUpdater.newUpdater(UnicastMonoProcessor.class, "state"); - - volatile int once; - - @SuppressWarnings("rawtypes") - static final AtomicIntegerFieldUpdater ONCE = - AtomicIntegerFieldUpdater.newUpdater(UnicastMonoProcessor.class, "once"); - - volatile Subscription subscription; - - @SuppressWarnings("rawtypes") - static final AtomicReferenceFieldUpdater UPSTREAM = - AtomicReferenceFieldUpdater.newUpdater( - UnicastMonoProcessor.class, Subscription.class, "subscription"); - - CoreSubscriber actual; - boolean hasDownstream = false; - - Throwable error; - O value; - - final MonoLifecycleHandler lifecycleHandler; - - UnicastMonoProcessor(MonoLifecycleHandler lifecycleHandler) { - this.lifecycleHandler = lifecycleHandler; - } - - @Override - @NonNull - public Context currentContext() { - final CoreSubscriber a = this.actual; - return a != null ? a.currentContext() : Context.empty(); - } - - @Override - public final void onSubscribe(Subscription subscription) { - if (Operators.setOnce(UPSTREAM, this, subscription)) { - subscription.request(Long.MAX_VALUE); - } - } - - @Override - public final void onComplete() { - onNext(null); - } - - @Override - public final void onError(Throwable cause) { - Objects.requireNonNull(cause, "onError cannot be null"); - - if (UPSTREAM.getAndSet(this, Operators.cancelledSubscription()) - == Operators.cancelledSubscription()) { - Operators.onErrorDropped(cause, currentContext()); - return; - } - - complete(cause); - } - - @Override - public final void onNext(@Nullable O value) { - final Subscription s; - if ((s = UPSTREAM.getAndSet(this, Operators.cancelledSubscription())) - == Operators.cancelledSubscription()) { - if (value != null) { - Operators.onNextDropped(value, currentContext()); - } - return; - } - - if (value == null) { - complete(); - } else { - if (s != null) { - s.cancel(); - } - - complete(value); - } - } - - /** - * Tries to emit the value and complete the underlying subscriber or stores the value away until - * there is a request for it. - * - *

Make sure this method is called at most once - * - * @param v the value to emit - */ - private void complete(O v) { - for (; ; ) { - int state = this.state; - - // if state is >= HAS_CANCELLED or bit zero is set (*_HAS_VALUE) case, return - if ((state & ~HAS_REQUEST_NO_RESULT) != 0) { - this.value = null; - Operators.onDiscard(v, currentContext()); - return; - } - - if (state == HAS_REQUEST_NO_RESULT) { - if (STATE.compareAndSet(this, HAS_REQUEST_NO_RESULT, HAS_REQUEST_HAS_RESULT)) { - final Subscriber a = actual; - hasDownstream = false; - value = null; - lifecycleHandler.doOnTerminal(SignalType.ON_COMPLETE, v, null); - a.onNext(v); - a.onComplete(); - return; - } - } - setValue(v); - if (state == NO_REQUEST_NO_RESULT - && STATE.compareAndSet(this, NO_REQUEST_NO_RESULT, NO_REQUEST_HAS_RESULT)) { - return; - } - if (state == NO_SUBSCRIBER_NO_RESULT - && STATE.compareAndSet(this, NO_SUBSCRIBER_NO_RESULT, NO_SUBSCRIBER_HAS_RESULT)) { - return; - } - } - } - - /** - * Tries to emit completion the underlying subscriber - * - *

Make sure this method is called at most once - */ - private void complete() { - for (; ; ) { - int state = this.state; - - // if state is >= HAS_CANCELLED or bit zero is set (*_HAS_VALUE) case, return - if ((state & ~HAS_REQUEST_NO_RESULT) != 0) { - return; - } - - if (state == HAS_REQUEST_NO_RESULT || state == NO_REQUEST_NO_RESULT) { - if (STATE.compareAndSet(this, state, HAS_REQUEST_HAS_RESULT)) { - final Subscriber a = actual; - hasDownstream = false; - lifecycleHandler.doOnTerminal(SignalType.ON_COMPLETE, null, null); - a.onComplete(); - return; - } - } - if (state == NO_SUBSCRIBER_NO_RESULT - && STATE.compareAndSet(this, NO_SUBSCRIBER_NO_RESULT, NO_SUBSCRIBER_HAS_RESULT)) { - return; - } - } - } - - /** - * Tries to emit error the underlying subscriber or stores the value away until there is a request - * for it. - * - *

Make sure this method is called at most once - * - * @param e the error to emit - */ - private void complete(Throwable e) { - for (; ; ) { - int state = this.state; - - // if state is >= HAS_CANCELLED or bit zero is set (*_HAS_VALUE) case, return - if ((state & ~HAS_REQUEST_NO_RESULT) != 0) { - return; - } - - setError(e); - if (state == HAS_REQUEST_NO_RESULT || state == NO_REQUEST_NO_RESULT) { - if (STATE.compareAndSet(this, state, HAS_REQUEST_HAS_RESULT)) { - final Subscriber a = actual; - hasDownstream = false; - lifecycleHandler.doOnTerminal(SignalType.ON_ERROR, null, e); - a.onError(e); - return; - } - } - if (state == NO_SUBSCRIBER_NO_RESULT - && STATE.compareAndSet(this, NO_SUBSCRIBER_NO_RESULT, NO_SUBSCRIBER_HAS_RESULT)) { - return; - } - } - } - - @Override - public void subscribe(CoreSubscriber actual) { - Objects.requireNonNull(actual, "subscribe"); - - if (once == 0 && ONCE.compareAndSet(this, 0, 1)) { - final MonoLifecycleHandler lh = this.lifecycleHandler; - - lh.doOnSubscribe(); - - this.hasDownstream = true; - this.actual = actual; - - int state = this.state; - - // possible states within the racing between [onNext / onComplete / onError / dispose] and - // setting subscriber - // are NO_SUBSCRIBER_[NO_RESULT or HAS_RESULT] - if (state == NO_SUBSCRIBER_NO_RESULT) { - if (STATE.compareAndSet(this, NO_SUBSCRIBER_NO_RESULT, NO_REQUEST_NO_RESULT)) { - state = NO_REQUEST_NO_RESULT; - } else { - // the possible false position is racing with [onNext / onError / onComplete / dispose] - // which are going to put the state in the NO_REQUEST_HAS_RESULT - STATE.set(this, NO_REQUEST_HAS_RESULT); - state = NO_REQUEST_HAS_RESULT; - } - } else { - STATE.set(this, NO_REQUEST_HAS_RESULT); - state = NO_REQUEST_HAS_RESULT; - } - - // check if state is with a result then there is a chance of immediate termination if there is - // no value - // e.g. [onError / onComplete / dispose] only - if (state == NO_REQUEST_HAS_RESULT && this.value == null) { - this.hasDownstream = false; - Throwable e = this.error; - // barrier to flush changes - STATE.set(this, HAS_REQUEST_HAS_RESULT); - if (e == null) { - lh.doOnTerminal(SignalType.ON_COMPLETE, null, null); - Operators.complete(actual); - } else { - lh.doOnTerminal(SignalType.ON_ERROR, null, e); - Operators.error(actual, e); - } - return; - } - - // call onSubscribe if has value in the result or no result delivered so far - actual.onSubscribe(this); - } else { - Operators.error( - actual, - new IllegalStateException("UnicastMonoProcessor allows only a single Subscriber")); - } - } - - @Override - public final void request(long n) { - if (Operators.validate(n)) { - for (; ; ) { - int s = state; - // if the any bits 1-31 are set, we are either in fusion mode (FUSED_*) - // or request has been called (HAS_REQUEST_*) - if ((s & ~NO_REQUEST_HAS_RESULT) != 0) { - return; - } - if (s == NO_REQUEST_HAS_RESULT) { - if (STATE.compareAndSet(this, NO_REQUEST_HAS_RESULT, HAS_REQUEST_HAS_RESULT)) { - final Subscriber a = actual; - final O v = value; - hasDownstream = false; - value = null; - lifecycleHandler.doOnTerminal(SignalType.ON_COMPLETE, v, null); - a.onNext(v); - a.onComplete(); - return; - } - } - if (STATE.compareAndSet(this, NO_REQUEST_NO_RESULT, HAS_REQUEST_NO_RESULT)) { - return; - } - } - } - } - - @Override - public final void cancel() { - if (STATE.getAndSet(this, CANCELLED) <= HAS_REQUEST_NO_RESULT) { - Operators.onDiscard(value, currentContext()); - value = null; - hasDownstream = false; - lifecycleHandler.doOnTerminal(SignalType.CANCEL, null, null); - final Subscription s = UPSTREAM.getAndSet(this, Operators.cancelledSubscription()); - if (s != null && s != Operators.cancelledSubscription()) { - s.cancel(); - } - } - } - - @Override - public void dispose() { - final Subscription s = UPSTREAM.getAndSet(this, Operators.cancelledSubscription()); - if (s == Operators.cancelledSubscription()) { - return; - } - - if (s != null) { - s.cancel(); - } - - complete(new CancellationException("Disposed")); - } - - /** - * Returns the value that completed this {@link UnicastMonoProcessor}. Returns {@code null} if the - * {@link UnicastMonoProcessor} has not been completed. If the {@link UnicastMonoProcessor} is - * completed with an error a RuntimeException that wraps the error is thrown. - * - * @return the value that completed the {@link UnicastMonoProcessor}, or {@code null} if it has - * not been completed - * @throws RuntimeException if the {@link UnicastMonoProcessor} was completed with an error - */ - @Nullable - public O peek() { - if (isCancelled()) { - return null; - } - - if (value != null) { - return value; - } - - if (error != null) { - RuntimeException re = Exceptions.propagate(error); - re = Exceptions.addSuppressed(re, new Exception("Mono#peek terminated with an error")); - throw re; - } - - return null; - } - - /** - * Set the value internally, without impacting request tracking state. - * - * @param value the new value. - * @see #complete(Object) - */ - private void setValue(O value) { - this.value = value; - } - - /** - * Set the error internally, without impacting request tracking state. - * - * @param throwable the error. - * @see #complete(Object) - */ - private void setError(Throwable throwable) { - this.error = throwable; - } - - /** - * Return the produced {@link Throwable} error if any or null - * - * @return the produced {@link Throwable} error if any or null - */ - @Nullable - public final Throwable getError() { - return isDisposed() ? error : null; - } - - /** - * Indicates whether this {@code UnicastMonoProcessor} has been completed with an error. - * - * @return {@code true} if this {@code UnicastMonoProcessor} was completed with an error, {@code - * false} otherwise. - */ - public final boolean isError() { - return getError() != null; - } - - /** - * Indicates whether this {@code UnicastMonoProcessor} has been interrupted via cancellation. - * - * @return {@code true} if this {@code UnicastMonoProcessor} is cancelled, {@code false} - * otherwise. - */ - public boolean isCancelled() { - return state == CANCELLED; - } - - public final boolean isTerminated() { - int state = this.state; - return (state < CANCELLED && state % 2 == 1); - } - - @Override - public boolean isDisposed() { - int state = this.state; - return state == CANCELLED || (state < CANCELLED && state % 2 == 1); - } - - @Override - @Nullable - public Object scanUnsafe(Attr key) { - // touch guard - int state = this.state; - - if (key == Attr.TERMINATED) { - return (state < CANCELLED && state % 2 == 1); - } - if (key == Attr.PARENT) { - return subscription; - } - if (key == Attr.ERROR) { - return error; - } - if (key == Attr.PREFETCH) { - return Integer.MAX_VALUE; - } - if (key == Attr.CANCELLED) { - return state == CANCELLED; - } - return null; - } - - /** - * Return true if any {@link Subscriber} is actively subscribed - * - * @return true if any {@link Subscriber} is actively subscribed - */ - public final boolean hasDownstream() { - return state > NO_SUBSCRIBER_HAS_RESULT && hasDownstream; - } -} diff --git a/rsocket-core/src/main/java/io/rsocket/util/DisposableUtils.java b/rsocket-core/src/main/java/io/rsocket/util/DisposableUtils.java deleted file mode 100644 index c87a08220..000000000 --- a/rsocket-core/src/main/java/io/rsocket/util/DisposableUtils.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2015-2018 the original author or authors. - * - * Licensed 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 io.rsocket.util; - -import java.util.Arrays; -import reactor.core.Disposable; - -/** Utilities for working with the {@link Disposable} type. */ -public final class DisposableUtils { - - private DisposableUtils() {} - - /** - * Calls the {@link Disposable#dispose()} method if the instance is not null. If any exceptions - * are thrown during disposal, suppress them. - * - * @param disposables the {@link Disposable}s to dispose - */ - public static void disposeQuietly(Disposable... disposables) { - Arrays.stream(disposables) - .forEach( - disposable -> { - try { - if (disposable != null) { - disposable.dispose(); - } - } catch (RuntimeException e) { - // Suppress any exceptions during disposal - } - }); - } -} diff --git a/rsocket-core/src/main/java/io/rsocket/util/DuplexConnectionProxy.java b/rsocket-core/src/main/java/io/rsocket/util/DuplexConnectionProxy.java deleted file mode 100644 index 2f5d1da4b..000000000 --- a/rsocket-core/src/main/java/io/rsocket/util/DuplexConnectionProxy.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2015-2019 the original author or authors. - * - * Licensed 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 io.rsocket.util; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.rsocket.DuplexConnection; -import org.reactivestreams.Publisher; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -public class DuplexConnectionProxy implements DuplexConnection { - private final DuplexConnection connection; - - public DuplexConnectionProxy(DuplexConnection connection) { - this.connection = connection; - } - - @Override - public Mono send(Publisher frames) { - return connection.send(frames); - } - - @Override - public Flux receive() { - return connection.receive(); - } - - @Override - public double availability() { - return connection.availability(); - } - - @Override - public ByteBufAllocator alloc() { - return connection.alloc(); - } - - @Override - public Mono onClose() { - return connection.onClose(); - } - - @Override - public void dispose() { - connection.dispose(); - } - - @Override - public boolean isDisposed() { - return connection.isDisposed(); - } - - public DuplexConnection delegate() { - return connection; - } -} diff --git a/rsocket-core/src/main/java/io/rsocket/util/Function3.java b/rsocket-core/src/main/java/io/rsocket/util/Function3.java deleted file mode 100644 index 5783665ae..000000000 --- a/rsocket-core/src/main/java/io/rsocket/util/Function3.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2015-2019 the original author or authors. - * - * Licensed 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 io.rsocket.util; - -public interface Function3 { - - R apply(T t, U u, V v); -} diff --git a/rsocket-core/src/main/java/io/rsocket/util/MonoLifecycleHandler.java b/rsocket-core/src/main/java/io/rsocket/util/MonoLifecycleHandler.java deleted file mode 100644 index 4d47c03d6..000000000 --- a/rsocket-core/src/main/java/io/rsocket/util/MonoLifecycleHandler.java +++ /dev/null @@ -1,21 +0,0 @@ -package io.rsocket.util; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import reactor.core.publisher.SignalType; - -public interface MonoLifecycleHandler { - - default void doOnSubscribe() {} - - /** - * Handler which is invoked on the terminal activity within a given Monoø - * - * @param signalType a type of signal which explain what happened - * @param element an carried element. May not be present if stream is empty or cancelled or - * errored - * @param e an carried error. May not be present if stream is cancelled or completed successfully - */ - default void doOnTerminal( - @Nonnull SignalType signalType, @Nullable T element, @Nullable Throwable e) {} -} diff --git a/rsocket-core/src/main/java/io/rsocket/util/MultiSubscriberRSocket.java b/rsocket-core/src/main/java/io/rsocket/util/MultiSubscriberRSocket.java deleted file mode 100644 index c2db6c238..000000000 --- a/rsocket-core/src/main/java/io/rsocket/util/MultiSubscriberRSocket.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2015-2019 the original author or authors. - * - * Licensed 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 io.rsocket.util; - -import io.rsocket.Payload; -import io.rsocket.RSocket; -import org.reactivestreams.Publisher; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -public class MultiSubscriberRSocket extends RSocketProxy { - public MultiSubscriberRSocket(RSocket source) { - super(source); - } - - @Override - public Mono fireAndForget(Payload payload) { - return Mono.defer(() -> super.fireAndForget(payload)); - } - - @Override - public Mono requestResponse(Payload payload) { - return Mono.defer(() -> super.requestResponse(payload)); - } - - @Override - public Flux requestStream(Payload payload) { - return Flux.defer(() -> super.requestStream(payload)); - } - - @Override - public Flux requestChannel(Publisher payloads) { - return Flux.defer(() -> super.requestChannel(payloads)); - } - - @Override - public Mono metadataPush(Payload payload) { - return Mono.defer(() -> super.metadataPush(payload)); - } -} diff --git a/rsocket-core/src/main/java/io/rsocket/util/OnceConsumer.java b/rsocket-core/src/main/java/io/rsocket/util/OnceConsumer.java deleted file mode 100644 index af4c038cc..000000000 --- a/rsocket-core/src/main/java/io/rsocket/util/OnceConsumer.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2015-2019 the original author or authors. - * - * Licensed 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 io.rsocket.util; - -import java.util.function.Consumer; - -public abstract class OnceConsumer implements Consumer { - private boolean isFirst = true; - - @Override - public final void accept(T t) { - if (isFirst) { - isFirst = false; - acceptOnce(t); - } - } - - public abstract void acceptOnce(T t); -} diff --git a/rsocket-core/src/main/java/io/rsocket/util/RecyclerFactory.java b/rsocket-core/src/main/java/io/rsocket/util/RecyclerFactory.java deleted file mode 100644 index 30385195c..000000000 --- a/rsocket-core/src/main/java/io/rsocket/util/RecyclerFactory.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2015-2018 the original author or authors. - * - * Licensed 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 io.rsocket.util; - -import io.netty.util.Recycler; -import io.netty.util.Recycler.Handle; -import java.util.Objects; -import java.util.function.Function; - -/** A factory for creating {@link Recycler}s. */ -public final class RecyclerFactory { - - /** - * Creates a new {@link Recycler}. - * - * @param newObjectCreator the {@link Function} to create a new object - * @param the type being recycled. - * @return the {@link Recycler} - * @throws NullPointerException if {@code newObjectCreator} is {@code null} - */ - public static Recycler createRecycler(Function, T> newObjectCreator) { - Objects.requireNonNull(newObjectCreator, "newObjectCreator must not be null"); - - return new Recycler() { - - @Override - protected T newObject(Handle handle) { - return newObjectCreator.apply(handle); - } - }; - } -} diff --git a/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterSubscribersTest.java b/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterSubscribersTest.java index 01cf99e26..fc87fc721 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterSubscribersTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterSubscribersTest.java @@ -26,7 +26,6 @@ import io.rsocket.lease.RequesterLeaseHandler; import io.rsocket.test.util.TestDuplexConnection; import io.rsocket.util.DefaultPayload; -import io.rsocket.util.MultiSubscriberRSocket; import java.time.Duration; import java.util.Arrays; import java.util.Collection; @@ -74,23 +73,6 @@ void setUp() { RequesterLeaseHandler.None); } - @ParameterizedTest - @MethodSource("allInteractions") - void multiSubscriber(Function> interaction) { - RSocket multiSubsRSocket = new MultiSubscriberRSocket(rSocketRequester); - Flux response = Flux.from(interaction.apply(multiSubsRSocket)); - StepVerifier.withVirtualTime(() -> response.take(Duration.ofMillis(10))) - .thenAwait(Duration.ofMillis(10)) - .expectComplete() - .verify(Duration.ofSeconds(5)); - StepVerifier.withVirtualTime(() -> response.take(Duration.ofMillis(10))) - .thenAwait(Duration.ofMillis(10)) - .expectComplete() - .verify(Duration.ofSeconds(5)); - - Assertions.assertThat(requestFramesCount(connection.getSent())).isEqualTo(2); - } - @ParameterizedTest @MethodSource("allInteractions") void singleSubscriber(Function> interaction) { diff --git a/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterTest.java b/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterTest.java index 3b62bc437..b6067cdeb 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterTest.java @@ -25,12 +25,10 @@ import static io.rsocket.frame.FrameType.REQUEST_STREAM; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; @@ -61,7 +59,6 @@ import io.rsocket.util.ByteBufPayload; import io.rsocket.util.DefaultPayload; import io.rsocket.util.EmptyPayload; -import io.rsocket.util.MultiSubscriberRSocket; import java.time.Duration; import java.util.ArrayList; import java.util.Iterator; @@ -249,21 +246,6 @@ public void testRequestReplyErrorOnSend() { // verify(responseSub).onError(any(RuntimeException.class)); } - @Test - @Timeout(2_000) - public void testLazyRequestResponse() { - Publisher response = - new MultiSubscriberRSocket(rule.socket).requestResponse(EmptyPayload.INSTANCE); - int streamId = sendRequestResponse(response); - Assertions.assertThat(rule.connection.getSent()).hasSize(1).allMatch(ReferenceCounted::release); - rule.assertHasNoLeaks(); - rule.connection.clearSendReceiveBuffers(); - int streamId2 = sendRequestResponse(response); - assertThat("Stream ID reused.", streamId2, not(equalTo(streamId))); - Assertions.assertThat(rule.connection.getSent()).hasSize(1).allMatch(ReferenceCounted::release); - rule.assertHasNoLeaks(); - } - @Test @Timeout(2_000) public void testChannelRequestCancellation() { diff --git a/rsocket-core/src/test/java/io/rsocket/internal/LimitableRequestPublisherTest.java b/rsocket-core/src/test/java/io/rsocket/internal/LimitableRequestPublisherTest.java deleted file mode 100644 index 8c51c123e..000000000 --- a/rsocket-core/src/test/java/io/rsocket/internal/LimitableRequestPublisherTest.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.rsocket.internal; - -import java.util.ArrayDeque; -import java.util.Queue; -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.RepeatedTest; -import org.junit.jupiter.api.Test; -import reactor.core.publisher.DirectProcessor; -import reactor.test.util.RaceTestUtils; - -class LimitableRequestPublisherTest { - - @Test - @RepeatedTest(2) - public void requestLimitRacingTest() throws InterruptedException { - Queue requests = new ArrayDeque<>(10000); - LimitableRequestPublisher limitableRequestPublisher = - LimitableRequestPublisher.wrap(DirectProcessor.create().doOnRequest(requests::add), 0); - - Runnable request1 = () -> limitableRequestPublisher.request(1); - Runnable request2 = () -> limitableRequestPublisher.increaseInternalLimit(2); - - limitableRequestPublisher.subscribe(); - - for (int i = 0; i < 10000; i++) { - RaceTestUtils.race(request1, request2); - } - - Thread.sleep(1000); - - Assertions.assertThat(requests.stream().mapToLong(l -> l).sum()).isEqualTo(10000); - } -} diff --git a/rsocket-core/src/test/java/io/rsocket/internal/SwitchTransformFluxTest.java b/rsocket-core/src/test/java/io/rsocket/internal/SwitchTransformFluxTest.java deleted file mode 100644 index 07fbf695f..000000000 --- a/rsocket-core/src/test/java/io/rsocket/internal/SwitchTransformFluxTest.java +++ /dev/null @@ -1,446 +0,0 @@ -package io.rsocket.internal; - -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasItem; - -import java.time.Duration; -import java.util.ArrayList; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; -import org.junit.Assert; -import org.junit.Assume; -import org.junit.Ignore; -import org.junit.Test; -import reactor.core.CoreSubscriber; -import reactor.core.publisher.Flux; -import reactor.core.scheduler.Schedulers; -import reactor.test.StepVerifier; -import reactor.test.publisher.TestPublisher; -import reactor.test.util.RaceTestUtils; -import reactor.util.context.Context; - -@Ignore -public class SwitchTransformFluxTest { - - @Test - public void shouldBeAbleToCancelSubscription() throws InterruptedException { - for (int j = 0; j < 10; j++) { - ArrayList capturedElements = new ArrayList<>(); - ArrayList capturedCompletions = new ArrayList<>(); - for (int i = 0; i < 1000; i++) { - TestPublisher publisher = TestPublisher.createCold(); - AtomicLong captureElement = new AtomicLong(0L); - AtomicBoolean captureCompletion = new AtomicBoolean(false); - AtomicLong requested = new AtomicLong(); - CountDownLatch latch = new CountDownLatch(1); - Flux switchTransformed = - publisher - .flux() - .doOnRequest(requested::addAndGet) - .doOnCancel(latch::countDown) - .transform( - flux -> new SwitchTransformFlux<>(flux, (first, innerFlux) -> innerFlux)); - - publisher.next(1L); - - switchTransformed.subscribe( - captureElement::set, - __ -> {}, - () -> captureCompletion.set(true), - s -> - new Thread( - () -> - RaceTestUtils.race( - publisher::complete, - () -> - RaceTestUtils.race( - s::cancel, () -> s.request(1), Schedulers.parallel()), - Schedulers.parallel())) - .start()); - - Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); - Assert.assertEquals(requested.get(), 1L); - capturedElements.add(captureElement.get()); - capturedCompletions.add(captureCompletion.get()); - } - - Assume.assumeThat(capturedElements, hasItem(equalTo(0L))); - Assume.assumeThat(capturedCompletions, hasItem(equalTo(false))); - } - } - - @Test - public void shouldRequestExpectedAmountOfElements() throws InterruptedException { - TestPublisher publisher = TestPublisher.createCold(); - AtomicLong capture = new AtomicLong(); - AtomicLong requested = new AtomicLong(); - CountDownLatch latch = new CountDownLatch(1); - Flux switchTransformed = - publisher - .flux() - .doOnRequest(requested::addAndGet) - .transform(flux -> new SwitchTransformFlux<>(flux, (first, innerFlux) -> innerFlux)); - - publisher.next(1L); - - switchTransformed.subscribe( - capture::set, - __ -> {}, - latch::countDown, - s -> { - for (int i = 0; i < 10000; i++) { - RaceTestUtils.race(() -> s.request(1), () -> s.request(1)); - } - RaceTestUtils.race(publisher::complete, publisher::complete); - }); - - latch.await(5, TimeUnit.SECONDS); - - Assert.assertEquals(capture.get(), 1L); - Assert.assertEquals(requested.get(), 20000L); - } - - @Test - public void shouldReturnCorrectContextOnEmptySource() { - Flux switchTransformed = - Flux.empty() - .transform(flux -> new SwitchTransformFlux<>(flux, (first, innerFlux) -> innerFlux)) - .subscriberContext(Context.of("a", "c")) - .subscriberContext(Context.of("c", "d")); - - StepVerifier.create(switchTransformed, 0) - .expectSubscription() - .thenRequest(1) - .expectAccessibleContext() - .contains("a", "c") - .contains("c", "d") - .then() - .expectComplete() - .verify(); - } - - @Test - public void shouldNotFailOnIncorrectPublisherBehavior() { - TestPublisher publisher = - TestPublisher.createNoncompliant(TestPublisher.Violation.CLEANUP_ON_TERMINATE); - Flux switchTransformed = - publisher - .flux() - .transform( - flux -> - new SwitchTransformFlux<>( - flux, - (first, innerFlux) -> innerFlux.subscriberContext(Context.of("a", "b")))); - - StepVerifier.create( - new Flux() { - @Override - public void subscribe(CoreSubscriber actual) { - switchTransformed.subscribe(actual); - publisher.next(1L); - } - }, - 0) - .thenRequest(1) - .expectNext(1L) - .thenRequest(1) - .then(() -> publisher.next(2L)) - .expectNext(2L) - .then(() -> publisher.error(new RuntimeException())) - .then(() -> publisher.error(new RuntimeException())) - .then(() -> publisher.error(new RuntimeException())) - .then(() -> publisher.error(new RuntimeException())) - .expectError() - .verifyThenAssertThat() - .hasDroppedErrors(3) - .tookLessThan(Duration.ofSeconds(10)); - - publisher.assertWasRequested(); - publisher.assertNoRequestOverflow(); - } - - // @Test - // public void shouldNotFailOnIncorrePu - - @Test - public void shouldBeAbleToAccessUpstreamContext() { - TestPublisher publisher = TestPublisher.createCold(); - - Flux switchTransformed = - publisher - .flux() - .transform( - flux -> - new SwitchTransformFlux<>( - flux, - (first, innerFlux) -> - innerFlux.map(String::valueOf).subscriberContext(Context.of("a", "b")))) - .subscriberContext(Context.of("a", "c")) - .subscriberContext(Context.of("c", "d")); - - publisher.next(1L); - - StepVerifier.create(switchTransformed, 0) - .thenRequest(1) - .expectNext("1") - .thenRequest(1) - .then(() -> publisher.next(2L)) - .expectNext("2") - .expectAccessibleContext() - .contains("a", "b") - .contains("c", "d") - .then() - .then(publisher::complete) - .expectComplete() - .verify(Duration.ofSeconds(10)); - - publisher.assertWasRequested(); - publisher.assertNoRequestOverflow(); - } - - @Test - public void shouldNotHangWhenOneElementUpstream() { - TestPublisher publisher = TestPublisher.createCold(); - - Flux switchTransformed = - publisher - .flux() - .transform( - flux -> - new SwitchTransformFlux<>( - flux, - (first, innerFlux) -> - innerFlux.map(String::valueOf).subscriberContext(Context.of("a", "b")))) - .subscriberContext(Context.of("a", "c")) - .subscriberContext(Context.of("c", "d")); - - publisher.next(1L); - publisher.complete(); - - StepVerifier.create(switchTransformed, 0) - .thenRequest(1) - .expectNext("1") - .expectComplete() - .verify(Duration.ofSeconds(10)); - - publisher.assertWasRequested(); - publisher.assertNoRequestOverflow(); - } - - @Test - public void backpressureTest() { - TestPublisher publisher = TestPublisher.createCold(); - AtomicLong requested = new AtomicLong(); - - Flux switchTransformed = - publisher - .flux() - .doOnRequest(requested::addAndGet) - .transform( - flux -> - new SwitchTransformFlux<>( - flux, (first, innerFlux) -> innerFlux.map(String::valueOf))); - - publisher.next(1L); - - StepVerifier.create(switchTransformed, 0) - .thenRequest(1) - .expectNext("1") - .thenRequest(1) - .then(() -> publisher.next(2L)) - .expectNext("2") - .then(publisher::complete) - .expectComplete() - .verify(Duration.ofSeconds(10)); - - publisher.assertWasRequested(); - publisher.assertNoRequestOverflow(); - - Assert.assertEquals(2L, requested.get()); - } - - @Test - public void backpressureConditionalTest() { - Flux publisher = Flux.range(0, 10000); - AtomicLong requested = new AtomicLong(); - - Flux switchTransformed = - publisher - .doOnRequest(requested::addAndGet) - .transform( - flux -> - new SwitchTransformFlux<>( - flux, (first, innerFlux) -> innerFlux.map(String::valueOf))) - .filter(e -> false); - - StepVerifier.create(switchTransformed, 0) - .thenRequest(1) - .expectComplete() - .verify(Duration.ofSeconds(10)); - - Assert.assertEquals(2L, requested.get()); - } - - @Test - public void backpressureHiddenConditionalTest() { - Flux publisher = Flux.range(0, 10000); - AtomicLong requested = new AtomicLong(); - - Flux switchTransformed = - publisher - .doOnRequest(requested::addAndGet) - .transform( - flux -> - new SwitchTransformFlux<>( - flux, (first, innerFlux) -> innerFlux.map(String::valueOf).hide())) - .filter(e -> false); - - StepVerifier.create(switchTransformed, 0) - .thenRequest(1) - .expectComplete() - .verify(Duration.ofSeconds(10)); - - Assert.assertEquals(10001L, requested.get()); - } - - @Test - public void backpressureDrawbackOnConditionalInTransformTest() { - Flux publisher = Flux.range(0, 10000); - AtomicLong requested = new AtomicLong(); - - Flux switchTransformed = - publisher - .doOnRequest(requested::addAndGet) - .transform( - flux -> - new SwitchTransformFlux<>( - flux, - (first, innerFlux) -> innerFlux.map(String::valueOf).filter(e -> false))); - - StepVerifier.create(switchTransformed, 0) - .thenRequest(1) - .expectComplete() - .verify(Duration.ofSeconds(10)); - - Assert.assertEquals(10001L, requested.get()); - } - - @Test - public void shouldErrorOnOverflowTest() { - TestPublisher publisher = TestPublisher.createCold(); - - Flux switchTransformed = - publisher - .flux() - .transform( - flux -> - new SwitchTransformFlux<>( - flux, (first, innerFlux) -> innerFlux.map(String::valueOf))); - - publisher.next(1L); - - StepVerifier.create(switchTransformed, 0) - .thenRequest(1) - .expectNext("1") - .then(() -> publisher.next(2L)) - .expectError() - .verify(Duration.ofSeconds(10)); - - publisher.assertWasRequested(); - publisher.assertNoRequestOverflow(); - } - - @Test - public void shouldPropagateonCompleteCorrectly() { - Flux switchTransformed = - Flux.empty() - .transform( - flux -> - new SwitchTransformFlux<>( - flux, (first, innerFlux) -> innerFlux.map(String::valueOf))); - - StepVerifier.create(switchTransformed).expectComplete().verify(Duration.ofSeconds(10)); - } - - @Test - public void shouldPropagateErrorCorrectly() { - Flux switchTransformed = - Flux.error(new RuntimeException("hello")) - .transform( - flux -> - new SwitchTransformFlux<>( - flux, (first, innerFlux) -> innerFlux.map(String::valueOf))); - - StepVerifier.create(switchTransformed) - .expectErrorMessage("hello") - .verify(Duration.ofSeconds(10)); - } - - @Test - public void shouldBeAbleToBeCancelledProperly() { - TestPublisher publisher = TestPublisher.createCold(); - Flux switchTransformed = - publisher - .flux() - .transform( - flux -> - new SwitchTransformFlux<>( - flux, (first, innerFlux) -> innerFlux.map(String::valueOf))); - - publisher.next(1); - - StepVerifier.create(switchTransformed, 0).thenCancel().verify(Duration.ofSeconds(10)); - - publisher.assertCancelled(); - publisher.assertWasRequested(); - } - - @Test - public void shouldBeAbleToCatchDiscardedElement() { - TestPublisher publisher = TestPublisher.createCold(); - Integer[] discarded = new Integer[1]; - Flux switchTransformed = - publisher - .flux() - .transform( - flux -> - new SwitchTransformFlux<>( - flux, (first, innerFlux) -> innerFlux.map(String::valueOf))) - .doOnDiscard(Integer.class, e -> discarded[0] = e); - - publisher.next(1); - - StepVerifier.create(switchTransformed, 0).thenCancel().verify(Duration.ofSeconds(10)); - - publisher.assertCancelled(); - publisher.assertWasRequested(); - - Assert.assertArrayEquals(new Integer[] {1}, discarded); - } - - @Test - public void shouldBeAbleToCatchDiscardedElementInCaseOfConditional() { - TestPublisher publisher = TestPublisher.createCold(); - Integer[] discarded = new Integer[1]; - Flux switchTransformed = - publisher - .flux() - .transform( - flux -> - new SwitchTransformFlux<>( - flux, (first, innerFlux) -> innerFlux.map(String::valueOf))) - .filter(t -> true) - .doOnDiscard(Integer.class, e -> discarded[0] = e); - - publisher.next(1); - - StepVerifier.create(switchTransformed, 0).thenCancel().verify(Duration.ofSeconds(10)); - - publisher.assertCancelled(); - publisher.assertWasRequested(); - - Assert.assertArrayEquals(new Integer[] {1}, discarded); - } -} diff --git a/rsocket-core/src/test/java/io/rsocket/internal/UnicastMonoEmptyTest.java b/rsocket-core/src/test/java/io/rsocket/internal/UnicastMonoEmptyTest.java deleted file mode 100644 index 76bb953a4..000000000 --- a/rsocket-core/src/test/java/io/rsocket/internal/UnicastMonoEmptyTest.java +++ /dev/null @@ -1,97 +0,0 @@ -package io.rsocket.internal; - -import static io.rsocket.internal.SchedulerUtils.warmup; - -import java.time.Duration; -import java.util.concurrent.atomic.AtomicInteger; -import org.assertj.core.api.Assertions; -import org.junit.Test; -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; -import reactor.test.util.RaceTestUtils; - -public class UnicastMonoEmptyTest { - - @Test - public void shouldSupportASingleSubscriber() throws InterruptedException { - warmup(Schedulers.single()); - - for (int i = 0; i < 10000; i++) { - AtomicInteger times = new AtomicInteger(); - Mono unicastMono = UnicastMonoEmpty.newInstance(times::incrementAndGet); - - Assertions.assertThatThrownBy( - () -> - RaceTestUtils.race( - unicastMono::subscribe, unicastMono::subscribe, Schedulers.single())) - .hasCause(new IllegalStateException("UnicastMonoEmpty allows only a single Subscriber")); - Assertions.assertThat(times.get()).isEqualTo(1); - } - } - - @Test - public void shouldSupportASingleBlock() throws InterruptedException { - warmup(Schedulers.single()); - - for (int i = 0; i < 10000; i++) { - AtomicInteger times = new AtomicInteger(); - Mono unicastMono = UnicastMonoEmpty.newInstance(times::incrementAndGet); - - Assertions.assertThatThrownBy( - () -> RaceTestUtils.race(unicastMono::block, unicastMono::block, Schedulers.single())) - .hasMessage("UnicastMonoEmpty allows only a single Subscriber"); - Assertions.assertThat(times.get()).isEqualTo(1); - } - } - - @Test - public void shouldSupportASingleBlockWithTimeout() throws InterruptedException { - warmup(Schedulers.single()); - - for (int i = 0; i < 10000; i++) { - AtomicInteger times = new AtomicInteger(); - Mono unicastMono = UnicastMonoEmpty.newInstance(times::incrementAndGet); - - Assertions.assertThatThrownBy( - () -> - RaceTestUtils.race( - () -> unicastMono.block(Duration.ofMinutes(1)), - () -> unicastMono.block(Duration.ofMinutes(1)), - Schedulers.single())) - .hasMessage("UnicastMonoEmpty allows only a single Subscriber"); - Assertions.assertThat(times.get()).isEqualTo(1); - } - } - - @Test - public void shouldSupportASingleSubscribeOrBlock() throws InterruptedException { - warmup(Schedulers.parallel()); - - for (int i = 0; i < 10000; i++) { - AtomicInteger times = new AtomicInteger(); - Mono unicastMono = UnicastMonoEmpty.newInstance(times::incrementAndGet); - - Assertions.assertThatThrownBy( - () -> - RaceTestUtils.race( - unicastMono::subscribe, - () -> - RaceTestUtils.race( - unicastMono::block, - () -> unicastMono.block(Duration.ofMinutes(1)), - Schedulers.parallel()), - Schedulers.parallel())) - .matches( - t -> { - Assertions.assertThat(t.getSuppressed()).hasSize(2); - Assertions.assertThat(t.getSuppressed()[0]) - .hasMessageContaining("UnicastMonoEmpty allows only a single Subscriber"); - Assertions.assertThat(t.getSuppressed()[1]) - .hasMessageContaining("UnicastMonoEmpty allows only a single Subscriber"); - - return true; - }); - Assertions.assertThat(times.get()).isEqualTo(1); - } - } -} diff --git a/rsocket-core/src/test/java/io/rsocket/internal/UnicastMonoProcessorTest.java b/rsocket-core/src/test/java/io/rsocket/internal/UnicastMonoProcessorTest.java deleted file mode 100644 index a836dd509..000000000 --- a/rsocket-core/src/test/java/io/rsocket/internal/UnicastMonoProcessorTest.java +++ /dev/null @@ -1,1780 +0,0 @@ -/* - * Copyright 2015-2018 the original author or authors. - * - * Licensed 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 io.rsocket.internal; - -import static io.rsocket.internal.SchedulerUtils.warmup; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import io.rsocket.internal.subscriber.AssertSubscriber; -import io.rsocket.util.MonoLifecycleHandler; -import java.lang.ref.WeakReference; -import java.time.Duration; -import java.util.ArrayList; -import java.util.Date; -import java.util.concurrent.CancellationException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; -import org.assertj.core.api.Assertions; -import org.junit.Test; -import org.reactivestreams.Subscriber; -import org.reactivestreams.Subscription; -import reactor.core.Scannable; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Hooks; -import reactor.core.publisher.Mono; -import reactor.core.publisher.MonoProcessor; -import reactor.core.publisher.Operators; -import reactor.core.publisher.SignalType; -import reactor.core.scheduler.Schedulers; -import reactor.test.StepVerifier; -import reactor.test.publisher.TestPublisher; -import reactor.test.util.RaceTestUtils; -import reactor.util.context.Context; -import reactor.util.function.Tuple2; - -public class UnicastMonoProcessorTest { - - static class VerifyMonoLifecycleHandler implements MonoLifecycleHandler { - private final AtomicInteger onSubscribeCounter = new AtomicInteger(); - private final AtomicInteger onTerminalCounter = new AtomicInteger(); - private final AtomicReference valueReference = new AtomicReference<>(); - private final AtomicReference errorReference = new AtomicReference<>(); - private final AtomicReference signalTypeReference = new AtomicReference<>(); - - @Override - public void doOnSubscribe() { - onSubscribeCounter.incrementAndGet(); - } - - @Override - public void doOnTerminal(SignalType signalType, T element, Throwable e) { - onTerminalCounter.incrementAndGet(); - signalTypeReference.set(signalType); - valueReference.set(element); - errorReference.set(e); - } - - public VerifyMonoLifecycleHandler assertSubscribed() { - assertThat(onSubscribeCounter.get()).isOne(); - return this; - } - - public VerifyMonoLifecycleHandler assertNotSubscribed() { - assertThat(onSubscribeCounter.get()).isZero(); - return this; - } - - public VerifyMonoLifecycleHandler assertTerminated() { - assertThat(onTerminalCounter.get()).describedAs("Expected a single terminal signal").isOne(); - return this; - } - - public VerifyMonoLifecycleHandler assertNotTerminated() { - assertThat(onTerminalCounter.get()).describedAs("Expected zero terminal signals").isZero(); - return this; - } - - public VerifyMonoLifecycleHandler assertCompleted() { - assertTerminated(); - assertThat(signalTypeReference.get()) - .describedAs("Expected ON_COMPLETE signal") - .isEqualTo(SignalType.ON_COMPLETE); - assertThat(errorReference.get()).describedAs("Expected error to be absent").isNull(); - assertThat(valueReference.get()).isNull(); - return this; - } - - public VerifyMonoLifecycleHandler assertCompleted(T value) { - assertTerminated(); - assertThat(signalTypeReference.get()) - .describedAs("Expected ON_COMPLETE signal") - .isEqualTo(SignalType.ON_COMPLETE); - assertThat(errorReference.get()).describedAs("Expected error to be absent").isNull(); - assertThat(valueReference.get()).isEqualTo(value); - return this; - } - - public VerifyMonoLifecycleHandler assertErrored() { - assertTerminated(); - assertThat(signalTypeReference.get()) - .describedAs("Expected ON_ERROR signal") - .isEqualTo(SignalType.ON_ERROR); - assertThat(errorReference.get()).describedAs("Expected error to be present").isNotNull(); - assertThat(valueReference.get()).isNull(); - return this; - } - - public VerifyMonoLifecycleHandler assertCancelled() { - assertTerminated(); - assertThat(signalTypeReference.get()) - .describedAs("Expected ON_ERROR signal") - .isEqualTo(SignalType.CANCEL); - assertThat(errorReference.get()).describedAs("Expected error to be absent").isNull(); - assertThat(valueReference.get()).isNull(); - return this; - } - } - - @Test - public void testUnicast() throws InterruptedException { - warmup(Schedulers.single()); - - for (int i = 0; i < 10000; i++) { - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - verifyMonoLifecycleHandler.assertNotSubscribed(); - assertThatThrownBy(() -> RaceTestUtils.race(processor::subscribe, processor::subscribe)) - .hasCause( - new IllegalStateException("UnicastMonoProcessor allows only a single Subscriber")); - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - } - } - - @Test - public void stateFlowTest1_Next() { - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - AssertSubscriber assertSubscriber = AssertSubscriber.create(0); - - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - processor.onNext(1); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_HAS_RESULT); - - processor.subscribe(assertSubscriber); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_REQUEST_HAS_RESULT); - - assertSubscriber.assertNoEvents(); - assertSubscriber.request(1); - - verifyMonoLifecycleHandler.assertCompleted(1); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_HAS_RESULT); - - assertSubscriber.assertValues(1); - assertSubscriber.assertComplete(); - } - - @Test - public void stateFlowTest1_Complete() { - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - AssertSubscriber assertSubscriber = AssertSubscriber.create(0); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - processor.onComplete(); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_HAS_RESULT); - - processor.subscribe(assertSubscriber); - - verifyMonoLifecycleHandler.assertSubscribed().assertCompleted(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_HAS_RESULT); - - assertSubscriber.assertNoValues(); - assertSubscriber.assertComplete(); - } - - @Test - public void stateFlowTest1_Error() { - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - AssertSubscriber assertSubscriber = AssertSubscriber.create(0); - RuntimeException testError = new RuntimeException("test"); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - processor.onError(testError); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_HAS_RESULT); - - processor.subscribe(assertSubscriber); - - verifyMonoLifecycleHandler.assertSubscribed().assertErrored(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_HAS_RESULT); - - assertSubscriber.assertNoValues(); - assertSubscriber.assertError(RuntimeException.class); - assertSubscriber.assertErrorMessage("test"); - } - - @Test - public void stateFlowTest1_Dispose() { - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - AssertSubscriber assertSubscriber = AssertSubscriber.create(0); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - processor.dispose(); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_HAS_RESULT); - - processor.subscribe(assertSubscriber); - - verifyMonoLifecycleHandler.assertSubscribed().assertErrored(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_HAS_RESULT); - - assertSubscriber.assertNoValues(); - assertSubscriber.assertError(CancellationException.class); - assertSubscriber.assertErrorMessage("Disposed"); - } - - @Test - public void stateFlowTest2_Next() { - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - AssertSubscriber assertSubscriber = AssertSubscriber.create(0); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - processor.subscribe(assertSubscriber); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_REQUEST_NO_RESULT); - - processor.onNext(1); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_REQUEST_HAS_RESULT); - - assertSubscriber.assertNoEvents(); - assertSubscriber.request(1); - - verifyMonoLifecycleHandler.assertSubscribed().assertCompleted(1); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_HAS_RESULT); - - assertSubscriber.assertValues(1); - assertSubscriber.assertComplete(); - } - - @Test - public void stateFlowTest2_Complete() { - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - AssertSubscriber assertSubscriber = AssertSubscriber.create(0); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - processor.subscribe(assertSubscriber); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_REQUEST_NO_RESULT); - - processor.onComplete(); - - verifyMonoLifecycleHandler.assertSubscribed().assertCompleted(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_HAS_RESULT); - - assertSubscriber.assertNoValues(); - assertSubscriber.assertComplete(); - } - - @Test - public void stateFlowTest2_Error() { - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - AssertSubscriber assertSubscriber = AssertSubscriber.create(0); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - processor.subscribe(assertSubscriber); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_REQUEST_NO_RESULT); - - processor.onError(new RuntimeException("Test")); - - verifyMonoLifecycleHandler.assertSubscribed().assertErrored(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_HAS_RESULT); - - assertSubscriber.assertNoValues(); - assertSubscriber.assertError(RuntimeException.class); - assertSubscriber.assertErrorMessage("Test"); - } - - @Test - public void stateFlowTest2_Dispose() { - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - AssertSubscriber assertSubscriber = AssertSubscriber.create(0); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - processor.subscribe(assertSubscriber); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_REQUEST_NO_RESULT); - - processor.dispose(); - - verifyMonoLifecycleHandler.assertSubscribed().assertErrored(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_HAS_RESULT); - - assertSubscriber.assertNoValues(); - assertSubscriber.assertError(CancellationException.class); - assertSubscriber.assertErrorMessage("Disposed"); - } - - @Test - public void stateFlowTest3_Next() { - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - AssertSubscriber assertSubscriber = AssertSubscriber.create(0); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - processor.subscribe(assertSubscriber); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_REQUEST_NO_RESULT); - - assertSubscriber.assertNoEvents(); - assertSubscriber.request(1); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_NO_RESULT); - - assertSubscriber.assertNoEvents(); - processor.onNext(1); - - verifyMonoLifecycleHandler.assertSubscribed().assertCompleted(1); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_HAS_RESULT); - - assertSubscriber.assertValues(1); - assertSubscriber.assertComplete(); - } - - @Test - public void stateFlowTest3_Complete() { - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - AssertSubscriber assertSubscriber = AssertSubscriber.create(0); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - processor.subscribe(assertSubscriber); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_REQUEST_NO_RESULT); - - assertSubscriber.request(1); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_NO_RESULT); - - processor.onComplete(); - - verifyMonoLifecycleHandler.assertSubscribed().assertCompleted(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_HAS_RESULT); - - assertSubscriber.assertNoValues(); - assertSubscriber.assertComplete(); - } - - @Test - public void stateFlowTest3_Error() { - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - AssertSubscriber assertSubscriber = AssertSubscriber.create(0); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - processor.subscribe(assertSubscriber); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_REQUEST_NO_RESULT); - - assertSubscriber.request(1); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_NO_RESULT); - - processor.onError(new RuntimeException("Test")); - - verifyMonoLifecycleHandler.assertSubscribed().assertErrored(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_HAS_RESULT); - - assertSubscriber.assertNoValues(); - assertSubscriber.assertError(RuntimeException.class); - assertSubscriber.assertErrorMessage("Test"); - } - - @Test - public void stateFlowTest3_Dispose() { - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - AssertSubscriber assertSubscriber = AssertSubscriber.create(0); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - processor.subscribe(assertSubscriber); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_REQUEST_NO_RESULT); - - assertSubscriber.request(1); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_NO_RESULT); - - processor.dispose(); - - verifyMonoLifecycleHandler.assertSubscribed().assertErrored(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_HAS_RESULT); - - assertSubscriber.assertNoValues(); - assertSubscriber.assertError(RuntimeException.class); - assertSubscriber.assertErrorMessage("Disposed"); - } - - @Test - public void stateFlowTest4_Next() { - ArrayList discarded = new ArrayList<>(); - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - // Context discardingContext = Operators.enableOnDiscard(null, discarded::add); - Hooks.onNextDropped(discarded::add); - AssertSubscriber assertSubscriber = new AssertSubscriber<>(0); - - try { - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - processor.subscribe(assertSubscriber); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_REQUEST_NO_RESULT); - - assertSubscriber.request(1); - assertSubscriber.assertNoEvents(); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_NO_RESULT); - - assertSubscriber.cancel(); - assertSubscriber.assertNoEvents(); - - verifyMonoLifecycleHandler.assertSubscribed().assertCancelled(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.CANCELLED); - - processor.onNext(1); - - verifyMonoLifecycleHandler.assertSubscribed().assertCancelled(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.CANCELLED); - - assertSubscriber.assertNoEvents(); - assertThat(discarded).containsExactly(1); - } finally { - Hooks.resetOnNextDropped(); - } - } - - @Test - public void stateFlowTest4_Error() { - ArrayList discarded = new ArrayList<>(); - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - // Context discardingContext = Operators.enableOnDiscard(null, discarded::add); - Hooks.onErrorDropped(discarded::add); - AssertSubscriber assertSubscriber = new AssertSubscriber<>(0); - - try { - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - processor.subscribe(assertSubscriber); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_REQUEST_NO_RESULT); - - assertSubscriber.request(1); - assertSubscriber.assertNoEvents(); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_NO_RESULT); - - assertSubscriber.cancel(); - assertSubscriber.assertNoEvents(); - - verifyMonoLifecycleHandler.assertSubscribed().assertCancelled(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.CANCELLED); - - RuntimeException testError = new RuntimeException("test"); - processor.onError(testError); - - verifyMonoLifecycleHandler.assertSubscribed().assertCancelled(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.CANCELLED); - - assertSubscriber.assertNoEvents(); - assertThat(discarded).containsExactly(testError); - - } finally { - Hooks.resetOnErrorDropped(); - } - } - - @Test - public void stateFlowTest4_Dispose() { - ArrayList discarded = new ArrayList<>(); - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - // Context discardingContext = Operators.enableOnDiscard(null, discarded::add); - Hooks.onErrorDropped(discarded::add); - try { - AssertSubscriber assertSubscriber = new AssertSubscriber<>(0); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - processor.subscribe(assertSubscriber); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_REQUEST_NO_RESULT); - - assertSubscriber.request(1); - assertSubscriber.assertNoEvents(); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_NO_RESULT); - - assertSubscriber.cancel(); - assertSubscriber.assertNoEvents(); - - verifyMonoLifecycleHandler.assertSubscribed().assertCancelled(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.CANCELLED); - - processor.dispose(); - - verifyMonoLifecycleHandler.assertSubscribed().assertCancelled(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.CANCELLED); - - assertSubscriber.assertNoEvents(); - assertThat(discarded).isEmpty(); - } finally { - Hooks.resetOnErrorDropped(); - } - } - - @Test - public void stateFlowTest4_Complete() { - ArrayList discarded = new ArrayList<>(); - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - // Context discardingContext = Operators.enableOnDiscard(null, discarded::add); - Hooks.onErrorDropped(discarded::add); - AssertSubscriber assertSubscriber = new AssertSubscriber<>(0); - - try { - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - processor.subscribe(assertSubscriber); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_REQUEST_NO_RESULT); - - assertSubscriber.request(1); - assertSubscriber.assertNoEvents(); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_NO_RESULT); - - assertSubscriber.cancel(); - assertSubscriber.assertNoEvents(); - - verifyMonoLifecycleHandler.assertSubscribed().assertCancelled(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.CANCELLED); - - processor.onComplete(); - - verifyMonoLifecycleHandler.assertSubscribed().assertCancelled(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.CANCELLED); - - assertSubscriber.assertNoEvents(); - assertThat(discarded).isEmpty(); - } finally { - Hooks.resetOnErrorDropped(); - } - } - - @Test - public void stateFlowTest5_Next() { - ArrayList discarded = new ArrayList<>(); - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - Context discardingContext = Operators.enableOnDiscard(null, discarded::add); - AssertSubscriber assertSubscriber = new AssertSubscriber<>(discardingContext, 0); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - processor.subscribe(assertSubscriber); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_REQUEST_NO_RESULT); - - processor.onNext(1); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_REQUEST_HAS_RESULT); - - assertSubscriber.cancel(); - - verifyMonoLifecycleHandler.assertSubscribed().assertCancelled(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.CANCELLED); - - assertSubscriber.request(1); - - verifyMonoLifecycleHandler.assertSubscribed().assertCancelled(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.CANCELLED); - - assertSubscriber.assertNoEvents(); - assertThat(discarded).containsExactly(1); - } - - @Test - public void stateFlowTest5_Complete() { - ArrayList discarded = new ArrayList<>(); - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - Context discardingContext = Operators.enableOnDiscard(null, discarded::add); - AssertSubscriber assertSubscriber = new AssertSubscriber<>(discardingContext, 0); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - processor.subscribe(assertSubscriber); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_REQUEST_NO_RESULT); - - processor.onComplete(); - - verifyMonoLifecycleHandler.assertSubscribed().assertCompleted(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_HAS_RESULT); - - assertSubscriber.cancel(); - - verifyMonoLifecycleHandler.assertSubscribed().assertCompleted(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.CANCELLED); - - assertSubscriber.assertComplete(); - assertThat(discarded).isEmpty(); - } - - @Test - public void stateFlowTest5_Error() { - ArrayList discarded = new ArrayList<>(); - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - Context discardingContext = Operators.enableOnDiscard(null, discarded::add); - Hooks.onErrorDropped(discarded::add); - AssertSubscriber assertSubscriber = new AssertSubscriber<>(discardingContext, 0); - - try { - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - processor.subscribe(assertSubscriber); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_REQUEST_NO_RESULT); - - processor.onError(new RuntimeException("test")); - - verifyMonoLifecycleHandler.assertSubscribed().assertErrored(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_HAS_RESULT); - - assertSubscriber.cancel(); - - verifyMonoLifecycleHandler.assertSubscribed().assertErrored(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.CANCELLED); - - assertSubscriber.assertError(RuntimeException.class); - assertSubscriber.assertErrorMessage("test"); - assertThat(discarded).isEmpty(); - } finally { - Hooks.resetOnErrorDropped(); - } - } - - @Test - public void stateFlowTest5_Dispose() { - ArrayList discarded = new ArrayList<>(); - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - Context discardingContext = Operators.enableOnDiscard(null, discarded::add); - Hooks.onErrorDropped(discarded::add); - AssertSubscriber assertSubscriber = new AssertSubscriber<>(discardingContext, 0); - - try { - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - processor.subscribe(assertSubscriber); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_REQUEST_NO_RESULT); - - processor.dispose(); - - verifyMonoLifecycleHandler.assertSubscribed().assertErrored(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_HAS_RESULT); - - assertSubscriber.cancel(); - - verifyMonoLifecycleHandler.assertSubscribed().assertErrored(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.CANCELLED); - - assertSubscriber.assertError(CancellationException.class); - assertSubscriber.assertErrorMessage("Disposed"); - assertThat(discarded).isEmpty(); - } finally { - Hooks.resetOnErrorDropped(); - } - } - - @Test - public void stateFlowTest6_Next() { - ArrayList discarded = new ArrayList<>(); - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - Context discardingContext = Operators.enableOnDiscard(null, discarded::add); - AssertSubscriber assertSubscriber = new AssertSubscriber<>(discardingContext, 0); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - processor.onNext(1); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_HAS_RESULT); - - processor.subscribe(assertSubscriber); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_REQUEST_HAS_RESULT); - - assertSubscriber.cancel(); - - verifyMonoLifecycleHandler.assertSubscribed().assertCancelled(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.CANCELLED); - - assertSubscriber.request(1); - - verifyMonoLifecycleHandler.assertSubscribed().assertCancelled(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.CANCELLED); - - assertSubscriber.assertNoEvents(); - assertThat(discarded).containsExactly(1); - } - - @Test - public void stateFlowTest7_Next() throws InterruptedException { - warmup(Schedulers.single()); - - for (int i = 0; i < 10000; i++) { - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - AssertSubscriber assertSubscriber = new AssertSubscriber<>(); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - RaceTestUtils.race( - () -> processor.onNext(1), - () -> processor.subscribe(assertSubscriber), - Schedulers.single()); - - verifyMonoLifecycleHandler.assertSubscribed().assertCompleted(1); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_HAS_RESULT); - - assertSubscriber.assertValues(1); - assertSubscriber.assertComplete(); - } - } - - @Test - public void stateFlowTest7_Complete() throws InterruptedException { - warmup(Schedulers.single()); - - for (int i = 0; i < 10000; i++) { - UnicastMonoProcessor processor = UnicastMonoProcessor.create(); - AssertSubscriber assertSubscriber = new AssertSubscriber<>(0); - - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - RaceTestUtils.race( - processor::onComplete, () -> processor.subscribe(assertSubscriber), Schedulers.single()); - - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_HAS_RESULT); - - assertSubscriber.assertNoValues(); - assertSubscriber.assertComplete(); - } - } - - @Test - public void stateFlowTest7_Error() throws InterruptedException { - warmup(Schedulers.single()); - - for (int i = 0; i < 10000; i++) { - UnicastMonoProcessor processor = UnicastMonoProcessor.create(); - AssertSubscriber assertSubscriber = new AssertSubscriber<>(0); - - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - RaceTestUtils.race( - () -> processor.onError(new RuntimeException("test")), - () -> processor.subscribe(assertSubscriber), - Schedulers.single()); - - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_HAS_RESULT); - - assertSubscriber.assertNoValues(); - assertSubscriber.assertError(RuntimeException.class); - assertSubscriber.assertErrorMessage("test"); - } - } - - @Test - public void stateFlowTest7_Dispose() throws InterruptedException { - warmup(Schedulers.single()); - - for (int i = 0; i < 10000; i++) { - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - AssertSubscriber assertSubscriber = new AssertSubscriber<>(0); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - RaceTestUtils.race( - processor::dispose, () -> processor.subscribe(assertSubscriber), Schedulers.single()); - - verifyMonoLifecycleHandler.assertSubscribed().assertErrored(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_HAS_RESULT); - - assertSubscriber.assertNoValues(); - assertSubscriber.assertError(CancellationException.class); - assertSubscriber.assertErrorMessage("Disposed"); - } - } - - @Test - public void stateFlowTest8_Next() throws InterruptedException { - warmup(Schedulers.single()); - - for (int i = 0; i < 10000; i++) { - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - AssertSubscriber assertSubscriber = new AssertSubscriber<>(); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - processor.subscribe(assertSubscriber); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_NO_RESULT); - - RaceTestUtils.race(() -> processor.onNext(1), assertSubscriber::cancel, Schedulers.single()); - - verifyMonoLifecycleHandler.assertSubscribed().assertTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.CANCELLED); - - if (assertSubscriber.values().isEmpty()) { - verifyMonoLifecycleHandler.assertSubscribed().assertCancelled(); - assertSubscriber.assertNoEvents(); - } else { - verifyMonoLifecycleHandler.assertSubscribed().assertCompleted(1); - assertSubscriber.assertValues(1); - assertSubscriber.assertComplete(); - } - } - } - - @Test - public void stateFlowTest9_Next() throws InterruptedException { - warmup(Schedulers.single()); - - for (int i = 0; i < 10000; i++) { - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - AssertSubscriber assertSubscriber = new AssertSubscriber<>(); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - processor.subscribe(assertSubscriber); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_NO_RESULT); - - RaceTestUtils.race(() -> processor.onNext(1), processor::dispose, Schedulers.single()); - - verifyMonoLifecycleHandler.assertSubscribed().assertTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_HAS_RESULT); - - if (processor.isError()) { - verifyMonoLifecycleHandler.assertSubscribed().assertErrored(); - assertSubscriber.assertNoValues(); - assertSubscriber.assertErrorMessage("Disposed"); - } else { - verifyMonoLifecycleHandler.assertSubscribed().assertCompleted(1); - assertSubscriber.assertValues(1); - assertSubscriber.assertComplete(); - } - } - } - - @Test - public void stateFlowTest13_Next() throws InterruptedException { - warmup(Schedulers.single()); - - for (int i = 0; i < 10000; i++) { - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - AssertSubscriber assertSubscriber = new AssertSubscriber<>(0); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - processor.onNext(1); - processor.subscribe(assertSubscriber); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - - RaceTestUtils.race( - () -> assertSubscriber.request(1), - () -> assertSubscriber.request(1), - Schedulers.single()); - - verifyMonoLifecycleHandler.assertSubscribed().assertCompleted(1); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_HAS_RESULT); - - assertSubscriber.assertValues(1); - assertSubscriber.assertComplete(); - } - } - - @Test - public void stateFlowTest14_Next() throws InterruptedException { - warmup(Schedulers.single()); - - for (int i = 0; i < 10000; i++) { - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - AssertSubscriber assertSubscriber = new AssertSubscriber<>(0); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - processor.subscribe(assertSubscriber); - assertSubscriber.request(1); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - RaceTestUtils.race(() -> processor.onNext(1), () -> processor.onNext(1), Schedulers.single()); - - verifyMonoLifecycleHandler.assertSubscribed().assertCompleted(1); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.HAS_REQUEST_HAS_RESULT); - - assertSubscriber.assertValues(1); - assertSubscriber.assertComplete(); - } - } - - @Test - public void stateFlowTest15_Next() throws InterruptedException { - warmup(Schedulers.single()); - - for (int i = 0; i < 10000; i++) { - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - AssertSubscriber assertSubscriber = new AssertSubscriber<>(0); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - processor.subscribe(assertSubscriber); - processor.onNext(1); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - RaceTestUtils.race( - () -> assertSubscriber.request(1), assertSubscriber::cancel, Schedulers.single()); - - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.CANCELLED); - - if (assertSubscriber.values().isEmpty()) { - verifyMonoLifecycleHandler.assertSubscribed().assertCancelled(); - assertSubscriber.assertNoEvents(); - } else { - verifyMonoLifecycleHandler.assertSubscribed().assertCompleted(1); - assertSubscriber.assertValues(1); - assertSubscriber.assertComplete(); - } - } - } - - @Test - public void stateFlowTest16_Next() throws InterruptedException { - warmup(Schedulers.single()); - - for (int i = 0; i < 10000; i++) { - VerifyMonoLifecycleHandler verifyMonoLifecycleHandler = - new VerifyMonoLifecycleHandler<>(); - UnicastMonoProcessor processor = - UnicastMonoProcessor.create(verifyMonoLifecycleHandler); - AssertSubscriber assertSubscriber = new AssertSubscriber<>(0); - - verifyMonoLifecycleHandler.assertNotSubscribed().assertNotTerminated(); - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.NO_SUBSCRIBER_NO_RESULT); - - processor.subscribe(assertSubscriber); - processor.onNext(1); - - verifyMonoLifecycleHandler.assertSubscribed().assertNotTerminated(); - RaceTestUtils.race(assertSubscriber::cancel, assertSubscriber::cancel, Schedulers.single()); - - assertThat(processor.state).isEqualTo(UnicastMonoProcessor.CANCELLED); - - verifyMonoLifecycleHandler.assertSubscribed().assertCancelled(); - assertSubscriber.assertNoEvents(); - } - } - - @Test - public void noRetentionOnTermination() throws InterruptedException { - Date date = new Date(); - CompletableFuture future = new CompletableFuture<>(); - - WeakReference refDate = new WeakReference<>(date); - WeakReference> refFuture = new WeakReference<>(future); - - Mono source = Mono.fromFuture(future); - Mono data = - source.map(Date::toString).log().subscribeWith(UnicastMonoProcessor.create()).log(); - - future.complete(date); - assertThat(data.block()).isEqualTo(date.toString()); - - date = null; - future = null; - source = null; - System.gc(); - - int cycles; - for (cycles = 10; cycles > 0; cycles--) { - if (refDate.get() == null && refFuture.get() == null) break; - Thread.sleep(100); - } - - assertThat(refFuture.get()).isNull(); - assertThat(refDate.get()).isNull(); - assertThat(cycles).isNotZero().isPositive(); - } - - @Test - public void noRetentionOnTerminationError() throws InterruptedException { - CompletableFuture future = new CompletableFuture<>(); - - WeakReference> refFuture = new WeakReference<>(future); - UnicastMonoProcessor processor = UnicastMonoProcessor.create(); - - Mono source = Mono.fromFuture(future); - Mono data = source.map(Date::toString).subscribeWith(processor); - - future.completeExceptionally(new IllegalStateException()); - - assertThatExceptionOfType(IllegalStateException.class).isThrownBy(data::block); - - future = null; - source = null; - System.gc(); - - int cycles; - for (cycles = 10; cycles > 0; cycles--) { - if (refFuture.get() == null) break; - Thread.sleep(100); - } - - assertThat(refFuture.get()).isNull(); - assertThat(cycles).isNotZero().isPositive(); - } - - @Test - public void noRetentionOnTerminationCancel() throws InterruptedException { - CompletableFuture future = new CompletableFuture<>(); - - WeakReference> refFuture = new WeakReference<>(future); - UnicastMonoProcessor processor = UnicastMonoProcessor.create(); - - Mono source = Mono.fromFuture(future); - Mono data = - source.map(Date::toString).transformDeferred((s) -> s.subscribeWith(processor)); - - future = null; - source = null; - - data.subscribe().dispose(); - processor.dispose(); - - data = null; - - System.gc(); - - int cycles; - for (cycles = 10; cycles > 0; cycles--) { - if (refFuture.get() == null) break; - Thread.sleep(100); - } - - assertThat(refFuture.get()).isNull(); - assertThat(cycles).isNotZero().isPositive(); - } - - @Test(expected = IllegalStateException.class) - public void MonoProcessorResultNotAvailable() { - MonoProcessor mp = MonoProcessor.create(); - mp.block(Duration.ofMillis(1)); - } - - @Test - public void MonoProcessorRejectedDoOnSuccessOrError() { - UnicastMonoProcessor mp = UnicastMonoProcessor.create(); - AtomicReference ref = new AtomicReference<>(); - - mp.doOnSuccessOrError((s, f) -> ref.set(f)).subscribe(); - mp.onError(new Exception("test")); - - assertThat(ref.get()).hasMessage("test"); - assertThat(mp.isError()).isTrue(); - } - - @Test - public void MonoProcessorRejectedDoOnTerminate() { - UnicastMonoProcessor mp = UnicastMonoProcessor.create(); - AtomicInteger invoked = new AtomicInteger(); - - mp.doOnTerminate(invoked::incrementAndGet).subscribe(); - mp.onError(new Exception("test")); - - assertThat(invoked.get()).isEqualTo(1); - assertThat(mp.isError()).isTrue(); - } - - @Test - public void MonoProcessorRejectedSubscribeCallback() { - UnicastMonoProcessor mp = UnicastMonoProcessor.create(); - AtomicReference ref = new AtomicReference<>(); - - mp.subscribe(v -> {}, ref::set); - mp.onError(new Exception("test")); - - assertThat(ref.get()).hasMessage("test"); - assertThat(mp.isError()).isTrue(); - } - - @Test - public void MonoProcessorSuccessDoOnSuccessOrError() { - UnicastMonoProcessor mp = UnicastMonoProcessor.create(); - AtomicReference ref = new AtomicReference<>(); - - mp.doOnSuccessOrError((s, f) -> ref.set(s)).subscribe(); - mp.onNext("test"); - - assertThat(ref.get()).isEqualToIgnoringCase("test"); - assertThat(mp.isDisposed()).isTrue(); - assertThat(mp.isError()).isFalse(); - } - - @Test - public void MonoProcessorSuccessDoOnTerminate() { - UnicastMonoProcessor mp = UnicastMonoProcessor.create(); - AtomicInteger invoked = new AtomicInteger(); - - mp.doOnTerminate(invoked::incrementAndGet).subscribe(); - mp.onNext("test"); - - assertThat(invoked.get()).isEqualTo(1); - assertThat(mp.isDisposed()).isTrue(); - assertThat(mp.isError()).isFalse(); - } - - @Test - public void MonoProcessorSuccessSubscribeCallback() { - UnicastMonoProcessor mp = UnicastMonoProcessor.create(); - AtomicReference ref = new AtomicReference<>(); - - mp.subscribe(ref::set); - mp.onNext("test"); - - assertThat(ref.get()).isEqualToIgnoringCase("test"); - assertThat(mp.isDisposed()).isTrue(); - assertThat(mp.isError()).isFalse(); - } - - @Test - public void MonoProcessorRejectedDoOnError() { - UnicastMonoProcessor mp = UnicastMonoProcessor.create(); - AtomicReference ref = new AtomicReference<>(); - - mp.doOnError(ref::set).subscribe(); - mp.onError(new Exception("test")); - - assertThat(ref.get()).hasMessage("test"); - assertThat(mp.isError()).isTrue(); - } - - @Test(expected = NullPointerException.class) - public void MonoProcessorRejectedSubscribeCallbackNull() { - UnicastMonoProcessor mp = UnicastMonoProcessor.create(); - - mp.subscribe((Subscriber) null); - } - - @Test - public void MonoProcessorSuccessDoOnSuccess() { - UnicastMonoProcessor mp = UnicastMonoProcessor.create(); - AtomicReference ref = new AtomicReference<>(); - - mp.doOnSuccess(ref::set).subscribe(); - mp.onNext("test"); - - assertThat(ref.get()).isEqualToIgnoringCase("test"); - assertThat(mp.isDisposed()).isTrue(); - assertThat(mp.isError()).isFalse(); - } - - @Test - public void MonoProcessorSuccessChainTogether() { - UnicastMonoProcessor mp = UnicastMonoProcessor.create(); - UnicastMonoProcessor mp2 = UnicastMonoProcessor.create(); - mp.subscribe(mp2); - - mp.onNext("test"); - - assertThat(mp2.peek()).isEqualToIgnoringCase("test"); - assertThat(mp.isDisposed()).isTrue(); - assertThat(mp.isError()).isFalse(); - } - - @Test - public void MonoProcessorRejectedChainTogether() { - UnicastMonoProcessor mp = UnicastMonoProcessor.create(); - UnicastMonoProcessor mp2 = UnicastMonoProcessor.create(); - mp.subscribe(mp2); - - mp.onError(new Exception("test")); - - assertThat(mp2.getError()).hasMessage("test"); - assertThat(mp.isError()).isTrue(); - } - - @Test - public void MonoProcessorDoubleFulfill() { - UnicastMonoProcessor mp = UnicastMonoProcessor.create(); - - StepVerifier.create(mp) - .then( - () -> { - mp.onNext("test1"); - mp.onNext("test2"); - }) - .expectNext("test1") - .expectComplete() - .verifyThenAssertThat() - .hasDroppedExactly("test2"); - } - - @Test - public void MonoProcessorNullFulfill() { - UnicastMonoProcessor mp = UnicastMonoProcessor.create(); - - mp.onNext(null); - - assertThat(mp.isDisposed()).isTrue(); - assertThat(mp.peek()).isNull(); - } - - @Test - public void MonoProcessorMapFulfill() { - UnicastMonoProcessor mp = UnicastMonoProcessor.create(); - - mp.onNext(1); - - UnicastMonoProcessor mp2 = - mp.map(s -> s * 2).subscribeWith(UnicastMonoProcessor.create()); - - assertThat(mp2.isDisposed()).isTrue(); - assertThat(mp2.isTerminated()).isTrue(); - assertThat(mp2.isCancelled()).isFalse(); - assertThat(mp2.peek()).isEqualTo(2); - - mp2.subscribe(); - } - - @Test - public void MonoProcessorThenFulfill() { - UnicastMonoProcessor mp = UnicastMonoProcessor.create(); - - mp.onNext(1); - - UnicastMonoProcessor mp2 = - mp.flatMap(s -> Mono.just(s * 2)).subscribeWith(UnicastMonoProcessor.create()); - - assertThat(mp2.isDisposed()).isTrue(); - assertThat(mp2.isTerminated()).isTrue(); - assertThat(mp2.isCancelled()).isFalse(); - assertThat(mp2.peek()).isEqualTo(2); - - mp2.subscribe(); - } - - @Test - public void MonoProcessorMapError() { - UnicastMonoProcessor mp = UnicastMonoProcessor.create(); - - mp.onNext(1); - - UnicastMonoProcessor mp2 = UnicastMonoProcessor.create(); - - StepVerifier.create( - mp.map( - s -> { - throw new RuntimeException("test"); - }) - .subscribeWith(mp2), - 0) - .thenRequest(1) - .then( - () -> { - assertThat(mp2.isDisposed()).isTrue(); - assertThat(mp2.getError()).hasMessage("test"); - }) - .verifyErrorMessage("test"); - } - - @Test(expected = Exception.class) - public void MonoProcessorDoubleError() { - UnicastMonoProcessor mp = UnicastMonoProcessor.create(); - - mp.onError(new Exception("test")); - mp.onError(new Exception("test")); - } - - @Test(expected = Exception.class) - public void MonoProcessorDoubleSignal() { - UnicastMonoProcessor mp = UnicastMonoProcessor.create(); - - mp.onNext("test"); - mp.onError(new Exception("test")); - } - - @Test - public void zipMonoProcessor() { - UnicastMonoProcessor mp = UnicastMonoProcessor.create(); - UnicastMonoProcessor mp2 = UnicastMonoProcessor.create(); - UnicastMonoProcessor> mp3 = UnicastMonoProcessor.create(); - - StepVerifier.create(Mono.zip(mp, mp2).subscribeWith(mp3), 0) - .then(() -> assertThat(mp3.isDisposed()).isFalse()) - .then(() -> mp.onNext(1)) - .then(() -> assertThat(mp3.isDisposed()).isFalse()) - .then(() -> mp2.onNext(2)) - .then( - () -> { - assertThat(mp3.isDisposed()).isTrue(); - assertThat(mp3.peek().getT1()).isEqualTo(1); - assertThat(mp3.peek().getT2()).isEqualTo(2); - }) - .thenRequest(1) - .expectNextMatches(t -> t.getT1() == 1 && t.getT2() == 2) - .verifyComplete(); - } - - @Test - public void zipMonoProcessor2() { - UnicastMonoProcessor mp = UnicastMonoProcessor.create(); - UnicastMonoProcessor mp3 = UnicastMonoProcessor.create(); - - StepVerifier.create(Mono.zip(d -> (Integer) d[0], mp).subscribeWith(mp3), 0) - .then(() -> assertThat(mp3.isDisposed()).isFalse()) - .then(() -> mp.onNext(1)) - .then( - () -> { - assertThat(mp3.isDisposed()).isTrue(); - assertThat(mp3.peek()).isEqualTo(1); - }) - .thenRequest(1) - .expectNext(1) - .verifyComplete(); - } - - @Test - public void zipMonoProcessorRejected() { - UnicastMonoProcessor mp = UnicastMonoProcessor.create(); - UnicastMonoProcessor mp2 = UnicastMonoProcessor.create(); - UnicastMonoProcessor> mp3 = UnicastMonoProcessor.create(); - - StepVerifier.create(Mono.zip(mp, mp2).subscribeWith(mp3)) - .then(() -> assertThat(mp3.isDisposed()).isFalse()) - .then(() -> mp.onError(new Exception("test"))) - .then( - () -> { - assertThat(mp3.isDisposed()).isTrue(); - assertThat(mp3.getError()).hasMessage("test"); - }) - .verifyErrorMessage("test"); - } - - @Test - public void filterMonoProcessor() { - UnicastMonoProcessor mp = UnicastMonoProcessor.create(); - UnicastMonoProcessor mp2 = UnicastMonoProcessor.create(); - StepVerifier.create(mp.filter(s -> s % 2 == 0).subscribeWith(mp2), 0) - .then(() -> mp.onNext(2)) - .then(() -> assertThat(mp2.isError()).isFalse()) - .then(() -> assertThat(mp2.isDisposed()).isTrue()) - .then(() -> assertThat(mp2.peek()).isEqualTo(2)) - .then(() -> assertThat(mp2.isDisposed()).isTrue()) - .thenRequest(1) - .expectNext(2) - .verifyComplete(); - } - - @Test - public void filterMonoProcessorNot() { - UnicastMonoProcessor mp = UnicastMonoProcessor.create(); - UnicastMonoProcessor mp2 = UnicastMonoProcessor.create(); - StepVerifier.create(mp.filter(s -> s % 2 == 0).subscribeWith(mp2)) - .then(() -> mp.onNext(1)) - .then(() -> assertThat(mp2.isError()).isFalse()) - .then(() -> assertThat(mp2.isDisposed()).isTrue()) - .then(() -> assertThat(mp2.peek()).isNull()) - .then(() -> assertThat(mp2.isDisposed()).isTrue()) - .verifyComplete(); - } - - @Test - public void filterMonoProcessorError() { - UnicastMonoProcessor mp = UnicastMonoProcessor.create(); - UnicastMonoProcessor mp2 = UnicastMonoProcessor.create(); - StepVerifier.create( - mp.filter( - s -> { - throw new RuntimeException("test"); - }) - .subscribeWith(mp2)) - .then(() -> mp.onNext(2)) - .then(() -> assertThat(mp2.isError()).isTrue()) - .then(() -> assertThat(mp2.isDisposed()).isTrue()) - .then(() -> assertThat(mp2.getError()).hasMessage("test")) - .then(() -> assertThat(mp2.isDisposed()).isTrue()) - .verifyErrorMessage("test"); - } - - @Test - public void doOnSuccessMonoProcessorError() { - UnicastMonoProcessor mp = UnicastMonoProcessor.create(); - UnicastMonoProcessor mp2 = UnicastMonoProcessor.create(); - AtomicReference ref = new AtomicReference<>(); - - StepVerifier.create( - mp.doOnSuccess( - s -> { - throw new RuntimeException("test"); - }) - .doOnError(ref::set) - .subscribeWith(mp2)) - .then(() -> mp.onNext(2)) - .then(() -> assertThat(mp2.isError()).isTrue()) - .then(() -> assertThat(ref.get()).hasMessage("test")) - .then(() -> assertThat(mp2.isDisposed()).isTrue()) - .then(() -> assertThat(mp2.getError()).hasMessage("test")) - .then(() -> assertThat(mp2.isDisposed()).isTrue()) - .verifyErrorMessage("test"); - } - - @Test - public void fluxCancelledByMonoProcessor() { - AtomicLong cancelCounter = new AtomicLong(); - Flux.range(1, 10) - .doOnCancel(cancelCounter::incrementAndGet) - .transformDeferred((s) -> s.subscribeWith(UnicastMonoProcessor.create())) - .subscribe(); - - assertThat(cancelCounter.get()).isEqualTo(1); - } - - @Test - public void cancelledByMonoProcessor() { - AtomicLong cancelCounter = new AtomicLong(); - UnicastMonoProcessor monoProcessor = - Mono.just("foo") - .doOnCancel(cancelCounter::incrementAndGet) - .subscribeWith(UnicastMonoProcessor.create()); - monoProcessor.subscribe(); - - assertThat(cancelCounter.get()).isEqualTo(1); - } - - @Test - public void scanProcessor() { - UnicastMonoProcessor test = UnicastMonoProcessor.create(); - Subscription subscription = Operators.emptySubscription(); - test.onSubscribe(subscription); - - assertThat(test.scan(Scannable.Attr.PREFETCH)).isEqualTo(Integer.MAX_VALUE); - assertThat(test.scan(Scannable.Attr.TERMINATED)).isFalse(); - assertThat(test.scan(Scannable.Attr.CANCELLED)).isFalse(); - - test.onComplete(); - assertThat(test.scan(Scannable.Attr.TERMINATED)).isTrue(); - assertThat(test.scan(Scannable.Attr.CANCELLED)).isFalse(); - } - - @Test - public void scanProcessorCancelled() { - UnicastMonoProcessor test = UnicastMonoProcessor.create(); - Subscription subscription = Operators.emptySubscription(); - test.onSubscribe(subscription); - - assertThat(test.scan(Scannable.Attr.PREFETCH)).isEqualTo(Integer.MAX_VALUE); - assertThat(test.scan(Scannable.Attr.TERMINATED)).isFalse(); - assertThat(test.scan(Scannable.Attr.CANCELLED)).isFalse(); - - test.cancel(); - assertThat(test.scan(Scannable.Attr.TERMINATED)).isFalse(); - assertThat(test.scan(Scannable.Attr.CANCELLED)).isTrue(); - } - - @Test - public void scanProcessorSubscription() { - UnicastMonoProcessor test = UnicastMonoProcessor.create(); - Subscription subscription = Operators.emptySubscription(); - test.onSubscribe(subscription); - - assertThat(test.scan(Scannable.Attr.ACTUAL)).isNull(); - assertThat(test.scan(Scannable.Attr.PARENT)).isSameAs(subscription); - } - - @Test - public void scanProcessorError() { - UnicastMonoProcessor test = UnicastMonoProcessor.create(); - Subscription subscription = Operators.emptySubscription(); - test.onSubscribe(subscription); - - test.onError(new IllegalStateException("boom")); - - assertThat(test.scan(Scannable.Attr.ERROR)).hasMessage("boom"); - } - - @Test - public void monoToProcessorConnects() { - TestPublisher tp = TestPublisher.create(); - UnicastMonoProcessor connectedProcessor = - tp.mono().subscribeWith(UnicastMonoProcessor.create()); - - assertThat(connectedProcessor.subscription).isNotNull(); - } - - @Test - public void monoToProcessorChain() { - StepVerifier.withVirtualTime( - () -> - Mono.just("foo") - .subscribeWith(UnicastMonoProcessor.create()) - .delayElement(Duration.ofMillis(500))) - .expectSubscription() - .expectNoEvent(Duration.ofMillis(500)) - .expectNext("foo") - .verifyComplete(); - } - - @Test - public void monoToProcessorChainColdToHot() { - AtomicInteger subscriptionCount = new AtomicInteger(); - Mono coldToHot = - Mono.just("foo") - .doOnSubscribe(sub -> subscriptionCount.incrementAndGet()) - .transformDeferred(s -> s.subscribeWith(UnicastMonoProcessor.create())) - .subscribeWith(UnicastMonoProcessor.create()) // this actually subscribes - .filter(s -> s.length() < 4); - - assertThat(subscriptionCount.get()).isEqualTo(1); - - coldToHot.block(); - assertThatThrownBy(coldToHot::block) - .hasMessage("UnicastMonoProcessor allows only a single Subscriber"); - assertThatThrownBy(coldToHot::block) - .hasMessage("UnicastMonoProcessor allows only a single Subscriber"); - - assertThat(subscriptionCount.get()).isEqualTo(1); - } - - @Test - public void monoProcessorBlockIsUnbounded() { - long start = System.nanoTime(); - - String result = - Mono.just("foo") - .delayElement(Duration.ofMillis(500)) - .subscribeWith(UnicastMonoProcessor.create()) - .block(); - - assertThat(result).isEqualTo("foo"); - assertThat(Duration.ofNanos(System.nanoTime() - start)) - .isGreaterThanOrEqualTo(Duration.ofMillis(500)); - } - - @Test - public void monoProcessorBlockNegativeIsImmediateTimeout() { - long start = System.nanoTime(); - - assertThatExceptionOfType(IllegalStateException.class) - .isThrownBy( - () -> - Mono.just("foo") - .delayElement(Duration.ofMillis(500)) - .subscribeWith(UnicastMonoProcessor.create()) - .block(Duration.ofSeconds(-1))) - .withMessage("Timeout on blocking read for -1000 MILLISECONDS"); - - assertThat(Duration.ofNanos(System.nanoTime() - start)).isLessThan(Duration.ofMillis(500)); - } - - @Test - public void monoProcessorBlockZeroIsImmediateTimeout() { - long start = System.nanoTime(); - - assertThatExceptionOfType(IllegalStateException.class) - .isThrownBy( - () -> - Mono.just("foo") - .delayElement(Duration.ofMillis(500)) - .subscribeWith(UnicastMonoProcessor.create()) - .block(Duration.ZERO)) - .withMessage("Timeout on blocking read for 0 MILLISECONDS"); - - assertThat(Duration.ofNanos(System.nanoTime() - start)).isLessThan(Duration.ofMillis(500)); - } - - @Test - public void disposeBeforeValueSendsCancellationException() { - UnicastMonoProcessor processor = UnicastMonoProcessor.create(); - AtomicReference e1 = new AtomicReference<>(); - AtomicReference e2 = new AtomicReference<>(); - AtomicReference e3 = new AtomicReference<>(); - AtomicReference late = new AtomicReference<>(); - - processor.subscribe(v -> Assertions.fail("expected first subscriber to error"), e1::set); - processor.subscribe(v -> Assertions.fail("expected second subscriber to error"), e2::set); - processor.subscribe(v -> Assertions.fail("expected third subscriber to error"), e3::set); - - processor.dispose(); - - assertThat(e1.get()).isInstanceOf(CancellationException.class); - assertThat(e2.get()).isInstanceOf(IllegalStateException.class); - assertThat(e3.get()).isInstanceOf(IllegalStateException.class); - - processor.subscribe(v -> Assertions.fail("expected late subscriber to error"), late::set); - assertThat(late.get()).isInstanceOf(IllegalStateException.class); - } -} From 388775c6bc36682e2fb45d68061e63bc8a3a42e1 Mon Sep 17 00:00:00 2001 From: Oleh Dokuka Date: Thu, 30 Apr 2020 17:31:54 +0300 Subject: [PATCH 08/25] adds generated JMH files cleanup --- benchmarks/build.gradle | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/benchmarks/build.gradle b/benchmarks/build.gradle index fa1d6e04b..f07f7c6f5 100644 --- a/benchmarks/build.gradle +++ b/benchmarks/build.gradle @@ -40,6 +40,10 @@ task jmhBaseline(type: JmhExecTask, description: 'Executing JMH baseline benchma classpath = sourceSets.main.runtimeClasspath + configurations.baseline } +clean { + delete "${projectDir}/src/main/generated" +} + class JmhExecTask extends JavaExec { private String include; @@ -160,4 +164,4 @@ class JmhExecTask extends JavaExec { super.exec(); } -} \ No newline at end of file +} From d97fd8d5fc1d74f9fb72340b6f1023e1d780f1a8 Mon Sep 17 00:00:00 2001 From: Oleh Dokuka Date: Thu, 30 Apr 2020 20:50:55 +0300 Subject: [PATCH 09/25] adds missing NPE catch in order to handle rare racing cases (#808) --- .../src/main/java/io/rsocket/core/RSocketRequester.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java index f762bfe99..f9d4b2afe 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java @@ -478,7 +478,7 @@ public void accept(long n) { frame = RequestChannelFrameFlyweight.encodeReleasingPayload( allocator, streamId, false, n, initialPayload); - } catch (IllegalReferenceCountException e) { + } catch (IllegalReferenceCountException | NullPointerException e) { return; } From 12fd30140d23f161ad59c29c6385860af1d19a09 Mon Sep 17 00:00:00 2001 From: Oleh Dokuka Date: Fri, 1 May 2020 10:51:20 +0300 Subject: [PATCH 10/25] provides supportive class to hide concurrency complexity (#807) --- .../io/rsocket/core/RSocketRequester.java | 417 ++++++++---------- .../java/io/rsocket/core/RequestOperator.java | 188 ++++++++ .../core/RSocketRequesterSubscribersTest.java | 30 ++ .../io/rsocket/core/RSocketRequesterTest.java | 155 ++++++- .../io/rsocket/core/SetupRejectionTest.java | 2 + 5 files changed, 566 insertions(+), 226 deletions(-) create mode 100644 rsocket-core/src/main/java/io/rsocket/core/RequestOperator.java diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java index f9d4b2afe..fabea217b 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java @@ -52,10 +52,8 @@ import java.nio.channels.ClosedChannelException; import java.util.concurrent.CancellationException; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import java.util.function.Consumer; -import java.util.function.LongConsumer; import java.util.function.Supplier; import javax.annotation.Nullable; import org.reactivestreams.Processor; @@ -66,6 +64,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.publisher.MonoProcessor; +import reactor.core.publisher.Operators; import reactor.core.publisher.SignalType; import reactor.core.publisher.UnicastProcessor; import reactor.util.concurrent.Queues; @@ -208,7 +207,6 @@ private Mono handleFireAndForget(Payload payload) { } final AtomicBoolean once = new AtomicBoolean(); - final int streamId = streamIdSupplier.nextStreamId(receivers); return Mono.defer( () -> { @@ -217,15 +215,14 @@ private Mono handleFireAndForget(Payload payload) { new IllegalStateException("FireAndForgetMono allows only a single subscriber")); } - return Mono.empty() - .doOnSubscribe( - (__) -> { - ByteBuf requestFrame = - RequestFireAndForgetFrameFlyweight.encodeReleasingPayload( - allocator, streamId, payload); + final int streamId = streamIdSupplier.nextStreamId(receivers); + final ByteBuf requestFrame = + RequestFireAndForgetFrameFlyweight.encodeReleasingPayload( + allocator, streamId, payload); - sendProcessor.onNext(requestFrame); - }); + sendProcessor.onNext(requestFrame); + + return Mono.empty(); }); } @@ -241,13 +238,10 @@ private Mono handleRequestResponse(final Payload payload) { return Mono.error(new IllegalArgumentException(INVALID_PAYLOAD_ERROR_MESSAGE)); } - int streamId = streamIdSupplier.nextStreamId(receivers); final UnboundedProcessor sendProcessor = this.sendProcessor; final UnicastProcessor receiver = UnicastProcessor.create(Queues.one().get()); final AtomicBoolean once = new AtomicBoolean(); - receivers.put(streamId, receiver); - return Mono.defer( () -> { if (once.getAndSet(true)) { @@ -257,21 +251,39 @@ private Mono handleRequestResponse(final Payload payload) { return receiver .next() - .doOnSubscribe( - (__) -> { - ByteBuf requestFrame = - RequestResponseFrameFlyweight.encodeReleasingPayload( - allocator, streamId, payload); - - sendProcessor.onNext(requestFrame); - }) - .doFinally( - signalType -> { - if (signalType == SignalType.CANCEL) { - sendProcessor.onNext(CancelFrameFlyweight.encode(allocator, streamId)); - } - removeStreamReceiver(streamId); - }) + .transform( + Operators.lift( + (s, actual) -> + new RequestOperator(actual) { + + @Override + void hookOnFirstRequest(long n) { + int streamId = streamIdSupplier.nextStreamId(receivers); + this.streamId = streamId; + + ByteBuf requestResponseFrame = + RequestResponseFrameFlyweight.encodeReleasingPayload( + allocator, streamId, payload); + + receivers.put(streamId, receiver); + sendProcessor.onNext(requestResponseFrame); + } + + @Override + void hookOnCancel() { + if (receivers.remove(streamId, receiver)) { + sendProcessor.onNext( + CancelFrameFlyweight.encode(allocator, streamId)); + } else { + payload.release(); + } + } + + @Override + public void hookOnTerminal(SignalType signalType) { + receivers.remove(streamId, receiver); + } + })) .doOnDiscard(ReferenceCounted.class, DROPPED_ELEMENTS_CONSUMER); }); } @@ -288,15 +300,10 @@ private Flux handleRequestStream(final Payload payload) { return Flux.error(new IllegalArgumentException(INVALID_PAYLOAD_ERROR_MESSAGE)); } - int streamId = streamIdSupplier.nextStreamId(receivers); - final UnboundedProcessor sendProcessor = this.sendProcessor; final UnicastProcessor receiver = UnicastProcessor.create(); - final AtomicInteger wip = new AtomicInteger(0); final AtomicBoolean once = new AtomicBoolean(); - receivers.put(streamId, receiver); - return Flux.defer( () -> { if (once.getAndSet(true)) { @@ -305,62 +312,50 @@ private Flux handleRequestStream(final Payload payload) { } return receiver - .doOnRequest( - new LongConsumer() { - - boolean firstRequest = true; - - @Override - public void accept(long n) { - if (firstRequest) { - firstRequest = false; - if (wip.getAndIncrement() != 0) { - // no need to do anything. - // stream was canceled and fist payload has already been discarded - return; - } - int missed = 1; - boolean firstHasBeenSent = false; - for (; ; ) { - if (!firstHasBeenSent) { - sendProcessor.onNext( - RequestStreamFrameFlyweight.encodeReleasingPayload( - allocator, streamId, n, payload)); - firstHasBeenSent = true; - } else { - // if first frame was sent but we cycling again, it means that wip was - // incremented at doOnCancel - sendProcessor.onNext(CancelFrameFlyweight.encode(allocator, streamId)); - return; - } - - missed = wip.addAndGet(-missed); - if (missed == 0) { - return; - } - } - } else if (!receiver.isDisposed()) { - sendProcessor.onNext(RequestNFrameFlyweight.encode(allocator, streamId, n)); - } - } - }) - .doFinally( - s -> { - if (s == SignalType.CANCEL) { - if (wip.getAndIncrement() != 0) { - return; - } - - // check if we need to release payload - // only applicable if the cancel appears earlier than actual request - if (payload.refCnt() > 0) { - payload.release(); - } else { - sendProcessor.onNext(CancelFrameFlyweight.encode(allocator, streamId)); - } - } - removeStreamReceiver(streamId); - }) + .transform( + Operators.lift( + (s, actual) -> + new RequestOperator(actual) { + + @Override + void hookOnFirstRequest(long n) { + int streamId = streamIdSupplier.nextStreamId(receivers); + this.streamId = streamId; + + ByteBuf requestStreamFrame = + RequestStreamFrameFlyweight.encodeReleasingPayload( + allocator, streamId, n, payload); + + receivers.put(streamId, receiver); + + sendProcessor.onNext(requestStreamFrame); + } + + @Override + void hookOnRemainingRequests(long n) { + if (receiver.isDisposed()) { + return; + } + + sendProcessor.onNext( + RequestNFrameFlyweight.encode(allocator, streamId, n)); + } + + @Override + void hookOnCancel() { + if (receivers.remove(streamId, receiver)) { + sendProcessor.onNext( + CancelFrameFlyweight.encode(allocator, streamId)); + } else { + payload.release(); + } + } + + @Override + void hookOnTerminal(SignalType signalType) { + receivers.remove(streamId); + } + })) .doOnDiscard(ReferenceCounted.class, DROPPED_ELEMENTS_CONSUMER); }); } @@ -394,141 +389,123 @@ private Flux handleChannel(Flux request) { private Flux handleChannel(Payload initialPayload, Flux inboundFlux) { final UnboundedProcessor sendProcessor = this.sendProcessor; - final int streamId = streamIdSupplier.nextStreamId(receivers); - final AtomicInteger wip = new AtomicInteger(0); final UnicastProcessor receiver = UnicastProcessor.create(); - final BaseSubscriber upstreamSubscriber = - new BaseSubscriber() { - boolean first = true; + return receiver.transform( + Operators.lift( + (s, actual) -> + new RequestOperator(actual) { - @Override - protected void hookOnSubscribe(Subscription subscription) { - // noops - } + final BaseSubscriber upstreamSubscriber = + new BaseSubscriber() { - @Override - protected void hookOnNext(Payload payload) { - if (first) { - // need to skip first since we have already sent it - // no need to release it since it was released earlier on the request establishment - // phase - first = false; - request(1); - return; - } - if (!PayloadValidationUtils.isValid(mtu, payload)) { - payload.release(); - cancel(); - final IllegalArgumentException t = - new IllegalArgumentException(INVALID_PAYLOAD_ERROR_MESSAGE); - errorConsumer.accept(t); - // no need to send any errors. - sendProcessor.onNext(CancelFrameFlyweight.encode(allocator, streamId)); - receiver.onError(t); - return; - } - final ByteBuf frame = - PayloadFrameFlyweight.encodeNextReleasingPayload(allocator, streamId, payload); - - sendProcessor.onNext(frame); - } + boolean first = true; - @Override - protected void hookOnComplete() { - ByteBuf frame = PayloadFrameFlyweight.encodeComplete(allocator, streamId); - sendProcessor.onNext(frame); - } + @Override + protected void hookOnSubscribe(Subscription subscription) { + // noops + } - @Override - protected void hookOnError(Throwable t) { - ByteBuf frame = ErrorFrameFlyweight.encode(allocator, streamId, t); - sendProcessor.onNext(frame); - receiver.onError(t); - } + @Override + protected void hookOnNext(Payload payload) { + if (first) { + // need to skip first since we have already sent it + // no need to release it since it was released earlier on the request + // establishment + // phase + first = false; + request(1); + return; + } + if (!PayloadValidationUtils.isValid(mtu, payload)) { + payload.release(); + cancel(); + final IllegalArgumentException t = + new IllegalArgumentException(INVALID_PAYLOAD_ERROR_MESSAGE); + errorConsumer.accept(t); + // no need to send any errors. + sendProcessor.onNext(CancelFrameFlyweight.encode(allocator, streamId)); + receiver.onError(t); + return; + } + final ByteBuf frame = + PayloadFrameFlyweight.encodeNextReleasingPayload( + allocator, streamId, payload); - @Override - protected void hookFinally(SignalType type) { - senders.remove(streamId, this); - } - }; - - return receiver - .doOnRequest( - new LongConsumer() { - - boolean firstRequest = true; - - @Override - public void accept(long n) { - if (firstRequest) { - firstRequest = false; - if (wip.getAndIncrement() != 0) { - // no need to do anything. - // stream was canceled and fist payload has already been discarded - return; + sendProcessor.onNext(frame); + } + + @Override + protected void hookOnComplete() { + ByteBuf frame = PayloadFrameFlyweight.encodeComplete(allocator, streamId); + sendProcessor.onNext(frame); + } + + @Override + protected void hookOnError(Throwable t) { + ByteBuf frame = ErrorFrameFlyweight.encode(allocator, streamId, t); + sendProcessor.onNext(frame); + receiver.onError(t); + } + + @Override + protected void hookFinally(SignalType type) { + senders.remove(streamId, this); + } + }; + + @Override + void hookOnFirstRequest(long n) { + final int streamId = streamIdSupplier.nextStreamId(receivers); + this.streamId = streamId; + + final ByteBuf frame = + RequestChannelFrameFlyweight.encodeReleasingPayload( + allocator, streamId, false, n, initialPayload); + + senders.put(streamId, upstreamSubscriber); + receivers.put(streamId, receiver); + + inboundFlux + .limitRate(Queues.SMALL_BUFFER_SIZE) + .doOnDiscard(ReferenceCounted.class, DROPPED_ELEMENTS_CONSUMER) + .subscribe(upstreamSubscriber); + + sendProcessor.onNext(frame); } - int missed = 1; - boolean firstHasBeenSent = false; - for (; ; ) { - if (!firstHasBeenSent) { - ByteBuf frame; - try { - frame = - RequestChannelFrameFlyweight.encodeReleasingPayload( - allocator, streamId, false, n, initialPayload); - } catch (IllegalReferenceCountException | NullPointerException e) { - return; - } - - senders.put(streamId, upstreamSubscriber); - receivers.put(streamId, receiver); - - inboundFlux - .limitRate(Queues.SMALL_BUFFER_SIZE) - .doOnDiscard(ReferenceCounted.class, DROPPED_ELEMENTS_CONSUMER) - .subscribe(upstreamSubscriber); - - sendProcessor.onNext(frame); - firstHasBeenSent = true; - } else { - // if first frame was sent but we cycling again, it means that wip was - // incremented at doOnCancel - senders.remove(streamId, upstreamSubscriber); - receivers.remove(streamId, receiver); - sendProcessor.onNext(CancelFrameFlyweight.encode(allocator, streamId)); + + @Override + void hookOnRemainingRequests(long n) { + if (receiver.isDisposed()) { return; } - missed = wip.addAndGet(-missed); - if (missed == 0) { - return; + sendProcessor.onNext(RequestNFrameFlyweight.encode(allocator, streamId, n)); + } + + @Override + void hookOnCancel() { + senders.remove(streamId, upstreamSubscriber); + if (receivers.remove(streamId, receiver)) { + sendProcessor.onNext(CancelFrameFlyweight.encode(allocator, streamId)); } } - } else { - sendProcessor.onNext(RequestNFrameFlyweight.encode(allocator, streamId, n)); - } - } - }) - .doOnError( - t -> { - upstreamSubscriber.cancel(); - receivers.remove(streamId, receiver); - }) - .doOnComplete(() -> receivers.remove(streamId, receiver)) - .doOnCancel( - () -> { - upstreamSubscriber.cancel(); - if (wip.getAndIncrement() != 0) { - return; - } - // need to send frame only if RequestChannelFrame was sent - if (receivers.remove(streamId, receiver)) { - sendProcessor.onNext(CancelFrameFlyweight.encode(allocator, streamId)); - } - }); + @Override + void hookOnTerminal(SignalType signalType) { + if (signalType == SignalType.ON_ERROR) { + upstreamSubscriber.cancel(); + } + receivers.remove(streamId, receiver); + } + + @Override + public void cancel() { + upstreamSubscriber.cancel(); + super.cancel(); + } + })); } private Mono handleMetadataPush(Payload payload) { @@ -552,14 +529,12 @@ private Mono handleMetadataPush(Payload payload) { new IllegalStateException("MetadataPushMono allows only a single subscriber")); } - return Mono.empty() - .doOnSubscribe( - (__) -> { - ByteBuf metadataPushFrame = - MetadataPushFrameFlyweight.encodeReleasingPayload(allocator, payload); + ByteBuf metadataPushFrame = + MetadataPushFrameFlyweight.encodeReleasingPayload(allocator, payload); - sendProcessor.onNextPrioritized(metadataPushFrame); - }); + sendProcessor.onNextPrioritized(metadataPushFrame); + + return Mono.empty(); }); } @@ -757,14 +732,6 @@ private void terminate(Throwable e) { onClose.onError(e); } - private void removeStreamReceiver(int streamId) { - /*on termination receivers are explicitly cleared to avoid removing from map while iterating over one - of its views*/ - if (terminationError == null) { - receivers.remove(streamId); - } - } - private void handleSendProcessorError(Throwable t) { connection.dispose(); } diff --git a/rsocket-core/src/main/java/io/rsocket/core/RequestOperator.java b/rsocket-core/src/main/java/io/rsocket/core/RequestOperator.java new file mode 100644 index 000000000..05f8d6b3c --- /dev/null +++ b/rsocket-core/src/main/java/io/rsocket/core/RequestOperator.java @@ -0,0 +1,188 @@ +package io.rsocket.core; + +import io.rsocket.Payload; +import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; +import org.reactivestreams.Subscription; +import reactor.core.CoreSubscriber; +import reactor.core.Fuseable; +import reactor.core.publisher.Operators; +import reactor.core.publisher.SignalType; +import reactor.util.context.Context; + +/** + * This is a support class for handling of request input, intended for use with {@link + * Operators#lift}. It ensures serial execution of cancellation vs first request signals and also + * provides hooks for separate handling of first vs subsequent {@link Subscription#request} + * invocations. + */ +abstract class RequestOperator + implements CoreSubscriber, Fuseable.QueueSubscription { + + final CoreSubscriber actual; + + Subscription s; + Fuseable.QueueSubscription qs; + + int streamId; + boolean firstRequest = true; + + volatile int wip; + static final AtomicIntegerFieldUpdater WIP = + AtomicIntegerFieldUpdater.newUpdater(RequestOperator.class, "wip"); + + RequestOperator(CoreSubscriber actual) { + this.actual = actual; + } + + /** + * Optional hook executed exactly once on the first {@link Subscription#request) invocation + * and right after the {@link Subscription#request} was propagated to the upstream subscription. + * + *

Note: this hook may not be invoked if cancellation happened before this invocation + */ + void hookOnFirstRequest(long n) {} + + /** + * Optional hook executed after the {@link Subscription#request} was propagated to the upstream + * subscription and excludes the first {@link Subscription#request} invocation. + */ + void hookOnRemainingRequests(long n) {} + + /** Optional hook executed after this {@link Subscription} cancelling. */ + void hookOnCancel() {} + + /** + * Optional hook executed after {@link org.reactivestreams.Subscriber} termination events + * (onError, onComplete). + * + * @param signalType the type of termination event that triggered the hook ({@link + * SignalType#ON_ERROR} or {@link SignalType#ON_COMPLETE}) + */ + void hookOnTerminal(SignalType signalType) {} + + @Override + public Context currentContext() { + return actual.currentContext(); + } + + @Override + public void request(long n) { + this.s.request(n); + if (!firstRequest) { + try { + this.hookOnRemainingRequests(n); + } catch (Throwable throwable) { + onError(throwable); + } + return; + } + this.firstRequest = false; + + if (WIP.getAndIncrement(this) != 0) { + return; + } + int missed = 1; + + boolean firstLoop = true; + for (; ; ) { + if (firstLoop) { + firstLoop = false; + try { + this.hookOnFirstRequest(n); + } catch (Throwable throwable) { + onError(throwable); + return; + } + } else { + try { + this.hookOnCancel(); + } catch (Throwable throwable) { + onError(throwable); + } + return; + } + + missed = WIP.addAndGet(this, -missed); + if (missed == 0) { + return; + } + } + } + + @Override + public void cancel() { + this.s.cancel(); + + if (WIP.getAndIncrement(this) != 0) { + return; + } + + hookOnCancel(); + } + + @Override + @SuppressWarnings("unchecked") + public void onSubscribe(Subscription s) { + if (Operators.validate(this.s, s)) { + this.s = s; + if (s instanceof Fuseable.QueueSubscription) { + this.qs = (Fuseable.QueueSubscription) s; + } + this.actual.onSubscribe(this); + } + } + + @Override + public void onNext(Payload t) { + this.actual.onNext(t); + } + + @Override + public void onError(Throwable t) { + this.actual.onError(t); + try { + this.hookOnTerminal(SignalType.ON_ERROR); + } catch (Throwable throwable) { + Operators.onErrorDropped(throwable, currentContext()); + } + } + + @Override + public void onComplete() { + this.actual.onComplete(); + try { + this.hookOnTerminal(SignalType.ON_COMPLETE); + } catch (Throwable throwable) { + Operators.onErrorDropped(throwable, currentContext()); + } + } + + @Override + public int requestFusion(int requestedMode) { + if (this.qs != null) { + return this.qs.requestFusion(requestedMode); + } else { + return Fuseable.NONE; + } + } + + @Override + public Payload poll() { + return this.qs.poll(); + } + + @Override + public int size() { + return this.qs.size(); + } + + @Override + public boolean isEmpty() { + return this.qs.isEmpty(); + } + + @Override + public void clear() { + this.qs.clear(); + } +} diff --git a/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterSubscribersTest.java b/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterSubscribersTest.java index fc87fc721..4a9d907fa 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterSubscribersTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterSubscribersTest.java @@ -22,7 +22,9 @@ import io.rsocket.buffer.LeaksTrackingByteBufAllocator; import io.rsocket.frame.FrameHeaderFlyweight; import io.rsocket.frame.FrameType; +import io.rsocket.frame.PayloadFrameFlyweight; import io.rsocket.frame.decoder.PayloadDecoder; +import io.rsocket.internal.subscriber.AssertSubscriber; import io.rsocket.lease.RequesterLeaseHandler; import io.rsocket.test.util.TestDuplexConnection; import io.rsocket.util.DefaultPayload; @@ -40,6 +42,7 @@ import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; import reactor.test.StepVerifier; +import reactor.test.util.RaceTestUtils; class RSocketRequesterSubscribersTest { @@ -89,6 +92,33 @@ void singleSubscriber(Function> interaction) { Assertions.assertThat(requestFramesCount(connection.getSent())).isEqualTo(1); } + @ParameterizedTest + @MethodSource("allInteractions") + void singleSubscriberInCaseOfRacing(Function> interaction) { + for (int i = 1; i < 20000; i += 2) { + Flux response = Flux.from(interaction.apply(rSocketRequester)); + AssertSubscriber assertSubscriberA = AssertSubscriber.create(); + AssertSubscriber assertSubscriberB = AssertSubscriber.create(); + + RaceTestUtils.race( + () -> response.subscribe(assertSubscriberA), () -> response.subscribe(assertSubscriberB)); + + connection.addToReceivedBuffer(PayloadFrameFlyweight.encodeComplete(connection.alloc(), i)); + + assertSubscriberA.assertTerminated(); + assertSubscriberB.assertTerminated(); + + Assertions.assertThat(new AssertSubscriber[] {assertSubscriberA, assertSubscriberB}) + .anySatisfy(as -> as.assertError(IllegalStateException.class)); + + Assertions.assertThat(connection.getSent()) + .hasSize(1) + .first() + .matches(bb -> REQUEST_TYPES.contains(FrameHeaderFlyweight.frameType(bb))); + connection.clearSendReceiveBuffers(); + } + } + @ParameterizedTest @MethodSource("allInteractions") void singleSubscriberInteractionsAreLazy(Function> interaction) { diff --git a/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterTest.java b/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterTest.java index b6067cdeb..d7cd8c24b 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterTest.java @@ -34,6 +34,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.util.CharsetUtil; import io.netty.util.ReferenceCountUtil; @@ -50,7 +51,9 @@ import io.rsocket.frame.FrameType; import io.rsocket.frame.PayloadFrameFlyweight; import io.rsocket.frame.RequestChannelFrameFlyweight; +import io.rsocket.frame.RequestFireAndForgetFrameFlyweight; import io.rsocket.frame.RequestNFrameFlyweight; +import io.rsocket.frame.RequestResponseFrameFlyweight; import io.rsocket.frame.RequestStreamFrameFlyweight; import io.rsocket.frame.decoder.PayloadDecoder; import io.rsocket.internal.subscriber.AssertSubscriber; @@ -534,7 +537,8 @@ private static Stream racingCases() { RaceTestUtils.race(() -> as.request(1), as::cancel); // ensures proper frames order if (rule.connection.getSent().size() > 0) { - Assertions.assertThat(rule.connection.getSent()).hasSize(2); + // + // Assertions.assertThat(rule.connection.getSent()).hasSize(2); Assertions.assertThat(rule.connection.getSent()) .element(0) .matches( @@ -771,6 +775,155 @@ static Stream encodeDecodePayloadCases() { Arguments.of(REQUEST_CHANNEL, 5, 5)); } + @Test + public void ensuresThatNoOpsMustHappenUntilSubscriptionInCaseOfFnfCall() { + Payload payload1 = ByteBufPayload.create("abc1"); + Mono fnf1 = rule.socket.fireAndForget(payload1); + + Payload payload2 = ByteBufPayload.create("abc2"); + Mono fnf2 = rule.socket.fireAndForget(payload2); + + Assertions.assertThat(rule.connection.getSent()).isEmpty(); + + // checks that fnf2 should have id 1 even though it was generated later than fnf1 + AssertSubscriber voidAssertSubscriber2 = fnf2.subscribeWith(AssertSubscriber.create(0)); + voidAssertSubscriber2.assertTerminated().assertNoError(); + Assertions.assertThat(rule.connection.getSent()) + .hasSize(1) + .first() + .matches(bb -> frameType(bb) == REQUEST_FNF) + .matches(bb -> FrameHeaderFlyweight.streamId(bb) == 1) + // ensures that this is fnf1 with abc2 data + .matches( + bb -> + ByteBufUtil.equals( + RequestFireAndForgetFrameFlyweight.data(bb), + Unpooled.wrappedBuffer("abc2".getBytes()))) + .matches(ReferenceCounted::release); + + rule.connection.clearSendReceiveBuffers(); + + // checks that fnf1 should have id 3 even though it was generated earlier + AssertSubscriber voidAssertSubscriber1 = fnf1.subscribeWith(AssertSubscriber.create(0)); + voidAssertSubscriber1.assertTerminated().assertNoError(); + Assertions.assertThat(rule.connection.getSent()) + .hasSize(1) + .first() + .matches(bb -> frameType(bb) == REQUEST_FNF) + .matches(bb -> FrameHeaderFlyweight.streamId(bb) == 3) + // ensures that this is fnf1 with abc1 data + .matches( + bb -> + ByteBufUtil.equals( + RequestFireAndForgetFrameFlyweight.data(bb), + Unpooled.wrappedBuffer("abc1".getBytes()))) + .matches(ReferenceCounted::release); + } + + @ParameterizedTest + @MethodSource("requestNInteractions") + public void ensuresThatNoOpsMustHappenUntilFirstRequestN( + FrameType frameType, BiFunction> interaction) { + Payload payload1 = ByteBufPayload.create("abc1"); + Publisher interaction1 = interaction.apply(rule, payload1); + + Payload payload2 = ByteBufPayload.create("abc2"); + Publisher interaction2 = interaction.apply(rule, payload2); + + Assertions.assertThat(rule.connection.getSent()).isEmpty(); + + AssertSubscriber assertSubscriber1 = AssertSubscriber.create(0); + interaction1.subscribe(assertSubscriber1); + AssertSubscriber assertSubscriber2 = AssertSubscriber.create(0); + interaction2.subscribe(assertSubscriber2); + assertSubscriber1.assertNotTerminated().assertNoError(); + assertSubscriber2.assertNotTerminated().assertNoError(); + // even though we subscribed, nothing should happen until the first requestN + Assertions.assertThat(rule.connection.getSent()).isEmpty(); + + // first request on the second interaction to ensure that stream id issuing on the first request + assertSubscriber2.request(1); + + Assertions.assertThat(rule.connection.getSent()) + .hasSize(1) + .first() + .matches(bb -> frameType(bb) == frameType) + .matches( + bb -> FrameHeaderFlyweight.streamId(bb) == 1, + "Expected to have stream ID {1} but got {" + + FrameHeaderFlyweight.streamId(rule.connection.getSent().iterator().next()) + + "}") + .matches( + bb -> { + switch (frameType) { + case REQUEST_RESPONSE: + return ByteBufUtil.equals( + RequestResponseFrameFlyweight.data(bb), + Unpooled.wrappedBuffer("abc2".getBytes())); + case REQUEST_STREAM: + return ByteBufUtil.equals( + RequestStreamFrameFlyweight.data(bb), + Unpooled.wrappedBuffer("abc2".getBytes())); + case REQUEST_CHANNEL: + return ByteBufUtil.equals( + RequestChannelFrameFlyweight.data(bb), + Unpooled.wrappedBuffer("abc2".getBytes())); + } + + return false; + }) + .matches(ReferenceCounted::release); + + rule.connection.clearSendReceiveBuffers(); + + assertSubscriber1.request(1); + Assertions.assertThat(rule.connection.getSent()) + .hasSize(1) + .first() + .matches(bb -> frameType(bb) == frameType) + .matches( + bb -> FrameHeaderFlyweight.streamId(bb) == 3, + "Expected to have stream ID {1} but got {" + + FrameHeaderFlyweight.streamId(rule.connection.getSent().iterator().next()) + + "}") + .matches( + bb -> { + switch (frameType) { + case REQUEST_RESPONSE: + return ByteBufUtil.equals( + RequestResponseFrameFlyweight.data(bb), + Unpooled.wrappedBuffer("abc1".getBytes())); + case REQUEST_STREAM: + return ByteBufUtil.equals( + RequestStreamFrameFlyweight.data(bb), + Unpooled.wrappedBuffer("abc1".getBytes())); + case REQUEST_CHANNEL: + return ByteBufUtil.equals( + RequestChannelFrameFlyweight.data(bb), + Unpooled.wrappedBuffer("abc1".getBytes())); + } + + return false; + }) + .matches(ReferenceCounted::release); + } + + private static Stream requestNInteractions() { + return Stream.of( + Arguments.of( + REQUEST_RESPONSE, + (BiFunction>) + (rule, payload) -> rule.socket.requestResponse(payload)), + Arguments.of( + REQUEST_STREAM, + (BiFunction>) + (rule, payload) -> rule.socket.requestStream(payload)), + Arguments.of( + REQUEST_CHANNEL, + (BiFunction>) + (rule, payload) -> rule.socket.requestChannel(Flux.just(payload)))); + } + public int sendRequestResponse(Publisher response) { Subscriber sub = TestSubscriber.create(); response.subscribe(sub); diff --git a/rsocket-core/src/test/java/io/rsocket/core/SetupRejectionTest.java b/rsocket-core/src/test/java/io/rsocket/core/SetupRejectionTest.java index db72c7775..4d5cdc0d5 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/SetupRejectionTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/SetupRejectionTest.java @@ -20,6 +20,7 @@ import java.time.Duration; import java.util.ArrayList; import java.util.List; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import reactor.core.publisher.Mono; import reactor.core.publisher.UnicastProcessor; @@ -47,6 +48,7 @@ void responderRejectSetup() { } @Test + @Disabled("FIXME: needs to be revised") void requesterStreamsTerminatedOnZeroErrorFrame() { LeaksTrackingByteBufAllocator allocator = LeaksTrackingByteBufAllocator.instrument(ByteBufAllocator.DEFAULT); From b60020e7d5b451313c6a55522ec6029df2d3bb89 Mon Sep 17 00:00:00 2001 From: Oleh Dokuka Date: Mon, 4 May 2020 11:00:23 +0300 Subject: [PATCH 11/25] provides `Payload` `refCnt` verification (#809) --- .../io/rsocket/core/RSocketRequester.java | 20 ++++++++ .../io/rsocket/core/RSocketResponder.java | 37 +++++++++++---- .../io/rsocket/core/RSocketRequesterTest.java | 25 ++++++++++ .../io/rsocket/core/RSocketResponderTest.java | 46 +++++++++++++++++++ 4 files changed, 118 insertions(+), 10 deletions(-) diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java index fabea217b..ced250620 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java @@ -195,6 +195,10 @@ public Mono onClose() { } private Mono handleFireAndForget(Payload payload) { + if (payload.refCnt() <= 0) { + return Mono.error(new IllegalReferenceCountException()); + } + Throwable err = checkAvailable(); if (err != null) { payload.release(); @@ -227,6 +231,10 @@ private Mono handleFireAndForget(Payload payload) { } private Mono handleRequestResponse(final Payload payload) { + if (payload.refCnt() <= 0) { + return Mono.error(new IllegalReferenceCountException()); + } + Throwable err = checkAvailable(); if (err != null) { payload.release(); @@ -289,6 +297,10 @@ public void hookOnTerminal(SignalType signalType) { } private Flux handleRequestStream(final Payload payload) { + if (payload.refCnt() <= 0) { + return Flux.error(new IllegalReferenceCountException()); + } + Throwable err = checkAvailable(); if (err != null) { payload.release(); @@ -371,6 +383,10 @@ private Flux handleChannel(Flux request) { (s, flux) -> { Payload payload = s.get(); if (payload != null) { + if (payload.refCnt() <= 0) { + return Mono.error(new IllegalReferenceCountException()); + } + if (!PayloadValidationUtils.isValid(mtu, payload)) { payload.release(); final IllegalArgumentException t = @@ -509,6 +525,10 @@ public void cancel() { } private Mono handleMetadataPush(Payload payload) { + if (payload.refCnt() <= 0) { + return Mono.error(new IllegalReferenceCountException()); + } + Throwable err = this.terminationError; if (err != null) { payload.release(); diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java index f5c4aecec..2f073ba8a 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java @@ -450,8 +450,32 @@ protected void hookOnSubscribe(Subscription s) { @Override protected void hookOnNext(Payload payload) { - if (!PayloadValidationUtils.isValid(mtu, payload)) { - payload.release(); + try { + if (!PayloadValidationUtils.isValid(mtu, payload)) { + payload.release(); + // specifically for requestChannel case so when Payload is invalid we will not be + // sending CancelFrame and ErrorFrame + // Note: CancelFrame is redundant and due to spec + // (https://github.com/rsocket/rsocket/blob/master/Protocol.md#request-channel) + // Upon receiving an ERROR[APPLICATION_ERROR|REJECTED|CANCELED|INVALID], the stream + // is + // terminated on both Requester and Responder. + // Upon sending an ERROR[APPLICATION_ERROR|REJECTED|CANCELED|INVALID], the stream is + // terminated on both the Requester and Responder. + if (requestChannel != null) { + channelProcessors.remove(streamId, requestChannel); + } + cancel(); + final IllegalArgumentException t = + new IllegalArgumentException(INVALID_PAYLOAD_ERROR_MESSAGE); + handleError(streamId, t); + return; + } + + ByteBuf byteBuf = + PayloadFrameFlyweight.encodeNextReleasingPayload(allocator, streamId, payload); + sendProcessor.onNext(byteBuf); + } catch (Throwable e) { // specifically for requestChannel case so when Payload is invalid we will not be // sending CancelFrame and ErrorFrame // Note: CancelFrame is redundant and due to spec @@ -464,15 +488,8 @@ protected void hookOnNext(Payload payload) { channelProcessors.remove(streamId, requestChannel); } cancel(); - final IllegalArgumentException t = - new IllegalArgumentException(INVALID_PAYLOAD_ERROR_MESSAGE); - handleError(streamId, t); - return; + handleError(streamId, e); } - - ByteBuf byteBuf = - PayloadFrameFlyweight.encodeNextReleasingPayload(allocator, streamId, payload); - sendProcessor.onNext(byteBuf); } @Override diff --git a/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterTest.java b/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterTest.java index d7cd8c24b..2117e195d 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterTest.java @@ -37,6 +37,7 @@ import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.util.CharsetUtil; +import io.netty.util.IllegalReferenceCountException; import io.netty.util.ReferenceCountUtil; import io.netty.util.ReferenceCounted; import io.rsocket.Payload; @@ -775,6 +776,30 @@ static Stream encodeDecodePayloadCases() { Arguments.of(REQUEST_CHANNEL, 5, 5)); } + @ParameterizedTest + @MethodSource("refCntCases") + public void ensureSendsErrorOnIllegalRefCntPayload( + BiFunction> sourceProducer) { + Payload invalidPayload = ByteBufPayload.create("test", "test"); + invalidPayload.release(); + + Publisher source = sourceProducer.apply(invalidPayload, rule.socket); + + StepVerifier.create(source, 0) + .expectError(IllegalReferenceCountException.class) + .verify(Duration.ofMillis(100)); + } + + private static Stream>> refCntCases() { + return Stream.of( + (p, r) -> r.fireAndForget(p), + (p, r) -> r.requestResponse(p), + (p, r) -> r.requestStream(p), + (p, r) -> r.requestChannel(Mono.just(p)), + (p, r) -> + r.requestChannel(Flux.just(EmptyPayload.INSTANCE, p).doOnSubscribe(s -> s.request(1)))); + } + @Test public void ensuresThatNoOpsMustHappenUntilSubscriptionInCaseOfFnfCall() { Payload payload1 = ByteBufPayload.create("abc1"); diff --git a/rsocket-core/src/test/java/io/rsocket/core/RSocketResponderTest.java b/rsocket-core/src/test/java/io/rsocket/core/RSocketResponderTest.java index 2dbf6715b..9ec2a2df1 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/RSocketResponderTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/RSocketResponderTest.java @@ -18,6 +18,7 @@ import static io.rsocket.core.PayloadValidationUtils.INVALID_PAYLOAD_ERROR_MESSAGE; import static io.rsocket.frame.FrameHeaderFlyweight.frameType; +import static io.rsocket.frame.FrameType.ERROR; import static io.rsocket.frame.FrameType.REQUEST_CHANNEL; import static io.rsocket.frame.FrameType.REQUEST_FNF; import static io.rsocket.frame.FrameType.REQUEST_N; @@ -711,6 +712,51 @@ static Stream encodeDecodePayloadCases() { Arguments.of(REQUEST_CHANNEL, 5, 5)); } + @ParameterizedTest + @MethodSource("refCntCases") + public void ensureSendsErrorOnIllegalRefCntPayload(FrameType frameType) { + rule.setAcceptingSocket( + new RSocket() { + @Override + public Mono requestResponse(Payload payload) { + Payload invalidPayload = ByteBufPayload.create("test", "test"); + invalidPayload.release(); + return Mono.just(invalidPayload); + } + + @Override + public Flux requestStream(Payload payload) { + Payload invalidPayload = ByteBufPayload.create("test", "test"); + invalidPayload.release(); + return Flux.just(invalidPayload); + } + + @Override + public Flux requestChannel(Publisher payloads) { + Payload invalidPayload = ByteBufPayload.create("test", "test"); + invalidPayload.release(); + return Flux.just(invalidPayload); + } + }); + + rule.sendRequest(1, frameType); + + Assertions.assertThat(rule.connection.getSent()) + .hasSize(1) + .first() + .matches( + bb -> frameType(bb) == ERROR, + "Expect frame type to be {" + + ERROR + + "} but was {" + + frameType(rule.connection.getSent().iterator().next()) + + "}"); + } + + private static Stream refCntCases() { + return Stream.of(REQUEST_RESPONSE, REQUEST_STREAM, REQUEST_CHANNEL); + } + public static class ServerSocketRule extends AbstractSocketRule { private RSocket acceptingSocket; From 202e27f9d8c9e3b74c154f3d7cb6f3f1d45036d9 Mon Sep 17 00:00:00 2001 From: Oleh Dokuka Date: Mon, 4 May 2020 13:58:54 +0300 Subject: [PATCH 12/25] provides ordered stream id issuing (#811) --- .../io/rsocket/core/RSocketConnector.java | 4 +- .../io/rsocket/core/RSocketRequester.java | 248 +++++++++--------- .../java/io/rsocket/core/RSocketServer.java | 4 +- .../test/java/io/rsocket/TestScheduler.java | 80 ++++++ .../java/io/rsocket/core/KeepAliveTest.java | 7 +- .../io/rsocket/core/RSocketLeaseTest.java | 4 +- .../core/RSocketRequesterSubscribersTest.java | 25 +- .../io/rsocket/core/RSocketRequesterTest.java | 48 +++- .../java/io/rsocket/core/RSocketTest.java | 4 +- .../io/rsocket/core/SetupRejectionTest.java | 6 +- 10 files changed, 292 insertions(+), 138 deletions(-) create mode 100644 rsocket-core/src/test/java/io/rsocket/TestScheduler.java diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java index a7eed8c76..4e47109cf 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java @@ -42,6 +42,7 @@ import java.util.function.Supplier; import reactor.core.Disposable; import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; import reactor.util.retry.Retry; public class RSocketConnector { @@ -293,7 +294,8 @@ public Mono connect(Supplier transportSupplier) { (int) keepAliveInterval.toMillis(), (int) keepAliveMaxLifeTime.toMillis(), keepAliveHandler, - requesterLeaseHandler); + requesterLeaseHandler, + Schedulers.single(Schedulers.parallel())); RSocket wrappedRSocketRequester = interceptors.initRequester(rSocketRequester); diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java index ced250620..a2bd3d9fd 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java @@ -67,6 +67,7 @@ import reactor.core.publisher.Operators; import reactor.core.publisher.SignalType; import reactor.core.publisher.UnicastProcessor; +import reactor.core.scheduler.Scheduler; import reactor.util.concurrent.Queues; /** @@ -105,6 +106,7 @@ class RSocketRequester implements RSocket { private final KeepAliveFramesAcceptor keepAliveFramesAcceptor; private volatile Throwable terminationError; private final MonoProcessor onClose; + private final Scheduler serialScheduler; RSocketRequester( DuplexConnection connection, @@ -115,7 +117,8 @@ class RSocketRequester implements RSocket { int keepAliveTickPeriod, int keepAliveAckTimeout, @Nullable KeepAliveHandler keepAliveHandler, - RequesterLeaseHandler leaseHandler) { + RequesterLeaseHandler leaseHandler, + Scheduler serialScheduler) { this.connection = connection; this.allocator = connection.alloc(); this.payloadDecoder = payloadDecoder; @@ -126,6 +129,7 @@ class RSocketRequester implements RSocket { this.senders = new SynchronizedIntObjectHashMap<>(); this.receivers = new SynchronizedIntObjectHashMap<>(); this.onClose = MonoProcessor.create(); + this.serialScheduler = serialScheduler; // DO NOT Change the order here. The Send processor must be subscribed to before receiving this.sendProcessor = new UnboundedProcessor<>(); @@ -212,22 +216,23 @@ private Mono handleFireAndForget(Payload payload) { final AtomicBoolean once = new AtomicBoolean(); - return Mono.defer( - () -> { - if (once.getAndSet(true)) { - return Mono.error( - new IllegalStateException("FireAndForgetMono allows only a single subscriber")); - } + return Mono.defer( + () -> { + if (once.getAndSet(true)) { + return Mono.error( + new IllegalStateException("FireAndForgetMono allows only a single subscriber")); + } - final int streamId = streamIdSupplier.nextStreamId(receivers); - final ByteBuf requestFrame = - RequestFireAndForgetFrameFlyweight.encodeReleasingPayload( - allocator, streamId, payload); + final int streamId = streamIdSupplier.nextStreamId(receivers); + final ByteBuf requestFrame = + RequestFireAndForgetFrameFlyweight.encodeReleasingPayload( + allocator, streamId, payload); - sendProcessor.onNext(requestFrame); + sendProcessor.onNext(requestFrame); - return Mono.empty(); - }); + return Mono.empty(); + }) + .subscribeOn(serialScheduler); } private Mono handleRequestResponse(final Payload payload) { @@ -292,6 +297,7 @@ public void hookOnTerminal(SignalType signalType) { receivers.remove(streamId, receiver); } })) + .subscribeOn(serialScheduler) .doOnDiscard(ReferenceCounted.class, DROPPED_ELEMENTS_CONSUMER); }); } @@ -368,6 +374,7 @@ void hookOnTerminal(SignalType signalType) { receivers.remove(streamId); } })) + .subscribeOn(serialScheduler, false) .doOnDiscard(ReferenceCounted.class, DROPPED_ELEMENTS_CONSUMER); }); } @@ -408,120 +415,125 @@ private Flux handleChannel(Payload initialPayload, Flux receiver = UnicastProcessor.create(); - return receiver.transform( - Operators.lift( - (s, actual) -> - new RequestOperator(actual) { + return receiver + .transform( + Operators.lift( + (s, actual) -> + new RequestOperator(actual) { - final BaseSubscriber upstreamSubscriber = - new BaseSubscriber() { + final BaseSubscriber upstreamSubscriber = + new BaseSubscriber() { - boolean first = true; + boolean first = true; - @Override - protected void hookOnSubscribe(Subscription subscription) { - // noops - } + @Override + protected void hookOnSubscribe(Subscription subscription) { + // noops + } - @Override - protected void hookOnNext(Payload payload) { - if (first) { - // need to skip first since we have already sent it - // no need to release it since it was released earlier on the request - // establishment - // phase - first = false; - request(1); - return; - } - if (!PayloadValidationUtils.isValid(mtu, payload)) { - payload.release(); - cancel(); - final IllegalArgumentException t = - new IllegalArgumentException(INVALID_PAYLOAD_ERROR_MESSAGE); - errorConsumer.accept(t); - // no need to send any errors. - sendProcessor.onNext(CancelFrameFlyweight.encode(allocator, streamId)); - receiver.onError(t); - return; - } - final ByteBuf frame = - PayloadFrameFlyweight.encodeNextReleasingPayload( - allocator, streamId, payload); - - sendProcessor.onNext(frame); - } + @Override + protected void hookOnNext(Payload payload) { + if (first) { + // need to skip first since we have already sent it + // no need to release it since it was released earlier on the + // request + // establishment + // phase + first = false; + request(1); + return; + } + if (!PayloadValidationUtils.isValid(mtu, payload)) { + payload.release(); + cancel(); + final IllegalArgumentException t = + new IllegalArgumentException(INVALID_PAYLOAD_ERROR_MESSAGE); + errorConsumer.accept(t); + // no need to send any errors. + sendProcessor.onNext( + CancelFrameFlyweight.encode(allocator, streamId)); + receiver.onError(t); + return; + } + final ByteBuf frame = + PayloadFrameFlyweight.encodeNextReleasingPayload( + allocator, streamId, payload); + + sendProcessor.onNext(frame); + } + + @Override + protected void hookOnComplete() { + ByteBuf frame = + PayloadFrameFlyweight.encodeComplete(allocator, streamId); + sendProcessor.onNext(frame); + } + + @Override + protected void hookOnError(Throwable t) { + ByteBuf frame = ErrorFrameFlyweight.encode(allocator, streamId, t); + sendProcessor.onNext(frame); + receiver.onError(t); + } - @Override - protected void hookOnComplete() { - ByteBuf frame = PayloadFrameFlyweight.encodeComplete(allocator, streamId); - sendProcessor.onNext(frame); + @Override + protected void hookFinally(SignalType type) { + senders.remove(streamId, this); + } + }; + + @Override + void hookOnFirstRequest(long n) { + final int streamId = streamIdSupplier.nextStreamId(receivers); + this.streamId = streamId; + + final ByteBuf frame = + RequestChannelFrameFlyweight.encodeReleasingPayload( + allocator, streamId, false, n, initialPayload); + + senders.put(streamId, upstreamSubscriber); + receivers.put(streamId, receiver); + + inboundFlux + .limitRate(Queues.SMALL_BUFFER_SIZE) + .doOnDiscard(ReferenceCounted.class, DROPPED_ELEMENTS_CONSUMER) + .subscribe(upstreamSubscriber); + + sendProcessor.onNext(frame); + } + + @Override + void hookOnRemainingRequests(long n) { + if (receiver.isDisposed()) { + return; } - @Override - protected void hookOnError(Throwable t) { - ByteBuf frame = ErrorFrameFlyweight.encode(allocator, streamId, t); - sendProcessor.onNext(frame); - receiver.onError(t); + sendProcessor.onNext(RequestNFrameFlyweight.encode(allocator, streamId, n)); + } + + @Override + void hookOnCancel() { + senders.remove(streamId, upstreamSubscriber); + if (receivers.remove(streamId, receiver)) { + sendProcessor.onNext(CancelFrameFlyweight.encode(allocator, streamId)); } + } - @Override - protected void hookFinally(SignalType type) { - senders.remove(streamId, this); + @Override + void hookOnTerminal(SignalType signalType) { + if (signalType == SignalType.ON_ERROR) { + upstreamSubscriber.cancel(); } - }; - - @Override - void hookOnFirstRequest(long n) { - final int streamId = streamIdSupplier.nextStreamId(receivers); - this.streamId = streamId; - - final ByteBuf frame = - RequestChannelFrameFlyweight.encodeReleasingPayload( - allocator, streamId, false, n, initialPayload); - - senders.put(streamId, upstreamSubscriber); - receivers.put(streamId, receiver); - - inboundFlux - .limitRate(Queues.SMALL_BUFFER_SIZE) - .doOnDiscard(ReferenceCounted.class, DROPPED_ELEMENTS_CONSUMER) - .subscribe(upstreamSubscriber); - - sendProcessor.onNext(frame); - } - - @Override - void hookOnRemainingRequests(long n) { - if (receiver.isDisposed()) { - return; - } - - sendProcessor.onNext(RequestNFrameFlyweight.encode(allocator, streamId, n)); - } - - @Override - void hookOnCancel() { - senders.remove(streamId, upstreamSubscriber); - if (receivers.remove(streamId, receiver)) { - sendProcessor.onNext(CancelFrameFlyweight.encode(allocator, streamId)); - } - } - - @Override - void hookOnTerminal(SignalType signalType) { - if (signalType == SignalType.ON_ERROR) { - upstreamSubscriber.cancel(); - } - receivers.remove(streamId, receiver); - } - - @Override - public void cancel() { - upstreamSubscriber.cancel(); - super.cancel(); - } - })); + receivers.remove(streamId, receiver); + } + + @Override + public void cancel() { + upstreamSubscriber.cancel(); + super.cancel(); + } + })) + .subscribeOn(serialScheduler, false); } private Mono handleMetadataPush(Payload payload) { diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java index 19f0c5008..d5d8cee0f 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java @@ -39,6 +39,7 @@ import java.util.function.Consumer; import java.util.function.Supplier; import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; public final class RSocketServer { private static final String SERVER_TAG = "server"; @@ -222,7 +223,8 @@ private Mono acceptSetup( setupPayload.keepAliveInterval(), setupPayload.keepAliveMaxLifetime(), keepAliveHandler, - requesterLeaseHandler); + requesterLeaseHandler, + Schedulers.single(Schedulers.parallel())); RSocket wrappedRSocketRequester = interceptors.initRequester(rSocketRequester); diff --git a/rsocket-core/src/test/java/io/rsocket/TestScheduler.java b/rsocket-core/src/test/java/io/rsocket/TestScheduler.java new file mode 100644 index 000000000..7bc98d45d --- /dev/null +++ b/rsocket-core/src/test/java/io/rsocket/TestScheduler.java @@ -0,0 +1,80 @@ +package io.rsocket; + +import java.util.Queue; +import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; +import reactor.core.Disposable; +import reactor.core.Disposables; +import reactor.core.Exceptions; +import reactor.core.scheduler.Scheduler; +import reactor.util.concurrent.Queues; + +/** + * This is an implementation of scheduler which allows task execution on the caller thread or + * scheduling it for thread which are currently working (with "work stealing" behaviour) + */ +public final class TestScheduler implements Scheduler { + + public static final Scheduler INSTANCE = new TestScheduler(); + + volatile int wip; + static final AtomicIntegerFieldUpdater WIP = + AtomicIntegerFieldUpdater.newUpdater(TestScheduler.class, "wip"); + + final Worker sharedWorker = new TestWorker(this); + final Queue tasks = Queues.unboundedMultiproducer().get(); + + private TestScheduler() {} + + @Override + public Disposable schedule(Runnable task) { + tasks.offer(task); + if (WIP.getAndIncrement(this) != 0) { + return Disposables.never(); + } + + int missed = 1; + + for (; ; ) { + for (; ; ) { + Runnable runnable = tasks.poll(); + + if (runnable == null) { + break; + } + + try { + runnable.run(); + } catch (Throwable t) { + Exceptions.throwIfFatal(t); + } + } + + missed = WIP.addAndGet(this, -missed); + if (missed == 0) { + return Disposables.never(); + } + } + } + + @Override + public Worker createWorker() { + return sharedWorker; + } + + static class TestWorker implements Worker { + + final TestScheduler parent; + + TestWorker(TestScheduler parent) { + this.parent = parent; + } + + @Override + public Disposable schedule(Runnable task) { + return parent.schedule(task); + } + + @Override + public void dispose() {} + } +} diff --git a/rsocket-core/src/test/java/io/rsocket/core/KeepAliveTest.java b/rsocket-core/src/test/java/io/rsocket/core/KeepAliveTest.java index e8f3f4190..7e465db08 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/KeepAliveTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/KeepAliveTest.java @@ -23,6 +23,7 @@ import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.Unpooled; import io.rsocket.RSocket; +import io.rsocket.TestScheduler; import io.rsocket.buffer.LeaksTrackingByteBufAllocator; import io.rsocket.exceptions.ConnectionErrorException; import io.rsocket.frame.FrameHeaderFlyweight; @@ -67,7 +68,8 @@ static RSocketState requester(int tickPeriod, int timeout) { tickPeriod, timeout, new DefaultKeepAliveHandler(connection), - RequesterLeaseHandler.None); + RequesterLeaseHandler.None, + TestScheduler.INSTANCE); return new RSocketState(rSocket, errors, allocator, connection); } @@ -94,7 +96,8 @@ static ResumableRSocketState resumableRequester(int tickPeriod, int timeout) { tickPeriod, timeout, new ResumableKeepAliveHandler(resumableConnection), - RequesterLeaseHandler.None); + RequesterLeaseHandler.None, + TestScheduler.INSTANCE); return new ResumableRSocketState(rSocket, errors, connection, resumableConnection, allocator); } diff --git a/rsocket-core/src/test/java/io/rsocket/core/RSocketLeaseTest.java b/rsocket-core/src/test/java/io/rsocket/core/RSocketLeaseTest.java index 51f5afc24..04d5fe174 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/RSocketLeaseTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/RSocketLeaseTest.java @@ -28,6 +28,7 @@ import io.netty.buffer.Unpooled; import io.rsocket.Payload; import io.rsocket.RSocket; +import io.rsocket.TestScheduler; import io.rsocket.buffer.LeaksTrackingByteBufAllocator; import io.rsocket.exceptions.Exceptions; import io.rsocket.frame.FrameHeaderFlyweight; @@ -98,7 +99,8 @@ void setUp() { 0, 0, null, - requesterLeaseHandler); + requesterLeaseHandler, + TestScheduler.INSTANCE); RSocket mockRSocketHandler = mock(RSocket.class); when(mockRSocketHandler.metadataPush(any())).thenReturn(Mono.empty()); diff --git a/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterSubscribersTest.java b/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterSubscribersTest.java index 4a9d907fa..3e7479af3 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterSubscribersTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterSubscribersTest.java @@ -19,6 +19,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.rsocket.RSocket; +import io.rsocket.TestScheduler; import io.rsocket.buffer.LeaksTrackingByteBufAllocator; import io.rsocket.frame.FrameHeaderFlyweight; import io.rsocket.frame.FrameType; @@ -28,7 +29,6 @@ import io.rsocket.lease.RequesterLeaseHandler; import io.rsocket.test.util.TestDuplexConnection; import io.rsocket.util.DefaultPayload; -import java.time.Duration; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; @@ -41,7 +41,6 @@ import org.junit.jupiter.params.provider.MethodSource; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; -import reactor.test.StepVerifier; import reactor.test.util.RaceTestUtils; class RSocketRequesterSubscribersTest { @@ -73,21 +72,25 @@ void setUp() { 0, 0, null, - RequesterLeaseHandler.None); + RequesterLeaseHandler.None, + TestScheduler.INSTANCE); } @ParameterizedTest @MethodSource("allInteractions") void singleSubscriber(Function> interaction) { Flux response = Flux.from(interaction.apply(rSocketRequester)); - StepVerifier.withVirtualTime(() -> response.take(Duration.ofMillis(10))) - .thenAwait(Duration.ofMillis(10)) - .expectComplete() - .verify(Duration.ofSeconds(5)); - StepVerifier.withVirtualTime(() -> response.take(Duration.ofMillis(10))) - .thenAwait(Duration.ofMillis(10)) - .expectError(IllegalStateException.class) - .verify(Duration.ofSeconds(5)); + + AssertSubscriber assertSubscriberA = AssertSubscriber.create(); + AssertSubscriber assertSubscriberB = AssertSubscriber.create(); + + response.subscribe(assertSubscriberA); + response.subscribe(assertSubscriberB); + + connection.addToReceivedBuffer(PayloadFrameFlyweight.encodeComplete(connection.alloc(), 1)); + + assertSubscriberA.assertTerminated(); + assertSubscriberB.assertTerminated(); Assertions.assertThat(requestFramesCount(connection.getSent())).isEqualTo(1); } diff --git a/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterTest.java b/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterTest.java index 2117e195d..56e6c9342 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterTest.java @@ -42,6 +42,7 @@ import io.netty.util.ReferenceCounted; import io.rsocket.Payload; import io.rsocket.RSocket; +import io.rsocket.TestScheduler; import io.rsocket.exceptions.ApplicationErrorException; import io.rsocket.exceptions.CustomRSocketException; import io.rsocket.exceptions.RejectedSetupException; @@ -949,6 +950,50 @@ private static Stream requestNInteractions() { (rule, payload) -> rule.socket.requestChannel(Flux.just(payload)))); } + @ParameterizedTest + @MethodSource("streamIdRacingCases") + public void ensuresCorrectOrderOfStreamIdIssuingInCaseOfRacing( + BiFunction> interaction1, + BiFunction> interaction2) { + for (int i = 1; i < 10000; i += 4) { + Payload payload = DefaultPayload.create("test"); + Publisher publisher1 = interaction1.apply(rule, payload); + Publisher publisher2 = interaction2.apply(rule, payload); + RaceTestUtils.race( + () -> publisher1.subscribe(AssertSubscriber.create()), + () -> publisher2.subscribe(AssertSubscriber.create())); + + Assertions.assertThat(rule.connection.getSent()) + .extracting(FrameHeaderFlyweight::streamId) + .containsExactly(i, i + 2); + rule.connection.getSent().clear(); + } + } + + public static Stream streamIdRacingCases() { + return Stream.of( + Arguments.of( + (BiFunction>) + (r, p) -> r.socket.fireAndForget(p), + (BiFunction>) + (r, p) -> r.socket.requestResponse(p)), + Arguments.of( + (BiFunction>) + (r, p) -> r.socket.requestResponse(p), + (BiFunction>) + (r, p) -> r.socket.requestStream(p)), + Arguments.of( + (BiFunction>) + (r, p) -> r.socket.requestStream(p), + (BiFunction>) + (r, p) -> r.socket.requestChannel(Flux.just(p))), + Arguments.of( + (BiFunction>) + (r, p) -> r.socket.requestChannel(Flux.just(p)), + (BiFunction>) + (r, p) -> r.socket.fireAndForget(p))); + } + public int sendRequestResponse(Publisher response) { Subscriber sub = TestSubscriber.create(); response.subscribe(sub); @@ -973,7 +1018,8 @@ protected RSocketRequester newRSocket() { 0, 0, null, - RequesterLeaseHandler.None); + RequesterLeaseHandler.None, + TestScheduler.INSTANCE); } public int getStreamIdForRequestType(FrameType expectedFrameType) { diff --git a/rsocket-core/src/test/java/io/rsocket/core/RSocketTest.java b/rsocket-core/src/test/java/io/rsocket/core/RSocketTest.java index 02c3dfca8..48ce150d6 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/RSocketTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/RSocketTest.java @@ -25,6 +25,7 @@ import io.netty.buffer.ByteBufAllocator; import io.rsocket.Payload; import io.rsocket.RSocket; +import io.rsocket.TestScheduler; import io.rsocket.buffer.LeaksTrackingByteBufAllocator; import io.rsocket.exceptions.ApplicationErrorException; import io.rsocket.exceptions.CustomRSocketException; @@ -492,7 +493,8 @@ public Flux requestChannel(Publisher payloads) { 0, 0, null, - RequesterLeaseHandler.None); + RequesterLeaseHandler.None, + TestScheduler.INSTANCE); } public void setRequestAcceptor(RSocket requestAcceptor) { diff --git a/rsocket-core/src/test/java/io/rsocket/core/SetupRejectionTest.java b/rsocket-core/src/test/java/io/rsocket/core/SetupRejectionTest.java index 4d5cdc0d5..388bfffeb 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/SetupRejectionTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/SetupRejectionTest.java @@ -64,7 +64,8 @@ void requesterStreamsTerminatedOnZeroErrorFrame() { 0, 0, null, - RequesterLeaseHandler.None); + RequesterLeaseHandler.None, + TestScheduler.INSTANCE); String errorMsg = "error"; @@ -101,7 +102,8 @@ void requesterNewStreamsTerminatedAfterZeroErrorFrame() { 0, 0, null, - RequesterLeaseHandler.None); + RequesterLeaseHandler.None, + TestScheduler.INSTANCE); conn.addToReceivedBuffer( ErrorFrameFlyweight.encode( From 4fa73124212c02ffa31fb4d0589cd289b1260446 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Mon, 4 May 2020 13:31:26 +0100 Subject: [PATCH 13/25] Add Javadoc to RSocketConnector and RSocketServer (#813) --- .../io/rsocket/core/RSocketConnector.java | 371 ++++++++++++++---- .../java/io/rsocket/core/RSocketServer.java | 228 +++++++++-- .../src/main/java/io/rsocket/core/Resume.java | 105 ++++- .../FragmentationDuplexConnection.java | 2 +- .../core/RSocketServerFragmentationTest.java | 6 +- 5 files changed, 598 insertions(+), 114 deletions(-) diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java index 4e47109cf..3d9345c4b 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java @@ -22,6 +22,7 @@ import io.rsocket.Payload; import io.rsocket.RSocket; import io.rsocket.SocketAcceptor; +import io.rsocket.fragmentation.FragmentationDuplexConnection; import io.rsocket.frame.SetupFrameFlyweight; import io.rsocket.frame.decoder.PayloadDecoder; import io.rsocket.internal.ClientServerInputMultiplexer; @@ -40,14 +41,36 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Supplier; +import javax.annotation.Nullable; import reactor.core.Disposable; import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; import reactor.util.retry.Retry; +/** + * The main class to use to establish a connection to an RSocket server. + * + *

To connect over TCP using default settings: + * + *

{@code
+ * import io.rsocket.transport.netty.client.TcpClientTransport;
+ *
+ * Mono rocketMono =
+ *         RSocketConnector.connectWith(TcpClientTransport.create("localhost", 7000));
+ * }
+ * + *

To customize connection settings before connecting: + * + *

{@code
+ * Mono rocketMono =
+ *         RSocketConnector.create()
+ *                 .metadataMimeType("message/x.rsocket.composite-metadata.v0")
+ *                 .dataMimeType("application/cbor")
+ *                 .connect(TcpClientTransport.create("localhost", 7000));
+ * }
+ */ public class RSocketConnector { private static final String CLIENT_TAG = "client"; - private static final int MIN_MTU_SIZE = 64; private static final BiConsumer INVALIDATE_FUNCTION = (r, i) -> r.onClose().subscribe(null, __ -> i.invalidate(), i::invalidate); @@ -55,13 +78,12 @@ public class RSocketConnector { private Payload setupPayload = EmptyPayload.INSTANCE; private String metadataMimeType = "application/binary"; private String dataMimeType = "application/binary"; - - private SocketAcceptor acceptor = SocketAcceptor.with(new RSocket() {}); - private InitializingInterceptorRegistry interceptors = new InitializingInterceptorRegistry(); - private Duration keepAliveInterval = Duration.ofSeconds(20); private Duration keepAliveMaxLifeTime = Duration.ofSeconds(90); + @Nullable private SocketAcceptor acceptor; + private InitializingInterceptorRegistry interceptors = new InitializingInterceptorRegistry(); + private Retry retrySpec; private Resume resume; private Supplier> leasesSupplier; @@ -73,53 +95,109 @@ public class RSocketConnector { private RSocketConnector() {} + /** + * Static factory method to create an {@code RSocketConnector} instance and customize default + * settings before connecting. To connect only, use {@link #connectWith(ClientTransport)}. + */ public static RSocketConnector create() { return new RSocketConnector(); } + /** + * Static factory method to connect with default settings, effectively a shortcut for: + * + *
+   * RSocketConnector.create().connectWith(transport);
+   * 
+ * + * @param transport the transport of choice to connect with + * @return a {@code Mono} with the connected RSocket + */ public static Mono connectWith(ClientTransport transport) { return RSocketConnector.create().connect(() -> transport); } + /** + * Provide a {@code Payload} with data and/or metadata for the initial {@code SETUP} frame. Data + * and metadata should be formatted according to the MIME types specified via {@link + * #dataMimeType(String)} and {@link #metadataMimeType(String)}. + * + * @param payload the payload containing data and/or metadata for the {@code SETUP} frame + * @return the same instance for method chaining + * @see SETUP + * Frame + */ public RSocketConnector setupPayload(Payload payload) { - this.setupPayload = payload; + this.setupPayload = Objects.requireNonNull(payload); return this; } + /** + * Set the MIME type to use for formatting payload data on the established connection. This is set + * in the initial {@code SETUP} frame sent to the server. + * + *

By default this is set to {@code "application/binary"}. + * + * @param dataMimeType the MIME type to be used for payload data + * @return the same instance for method chaining + * @see SETUP + * Frame + */ public RSocketConnector dataMimeType(String dataMimeType) { - this.dataMimeType = dataMimeType; + this.dataMimeType = Objects.requireNonNull(dataMimeType); return this; } + /** + * Set the MIME type to use for formatting payload metadata on the established connection. This is + * set in the initial {@code SETUP} frame sent to the server. + * + *

For metadata encoding, consider using one of the following encoders: + * + *

    + *
  • {@link io.rsocket.metadata.CompositeMetadataFlyweight Composite Metadata} + *
  • {@link io.rsocket.metadata.TaggingMetadataFlyweight Routing} + *
  • {@link io.rsocket.metadata.security.AuthMetadataFlyweight Authentication} + *
+ * + *

For more on the above metadata formats, see the corresponding protocol extensions + * + *

By default this is set to {@code "application/binary"}. + * + * @param metadataMimeType the MIME type to be used for payload metadata + * @return the same instance for method chaining + * @see SETUP + * Frame + */ public RSocketConnector metadataMimeType(String metadataMimeType) { - this.metadataMimeType = metadataMimeType; - return this; - } - - public RSocketConnector interceptors(Consumer consumer) { - consumer.accept(this.interceptors); - return this; - } - - public RSocketConnector acceptor(SocketAcceptor acceptor) { - this.acceptor = acceptor; + this.metadataMimeType = Objects.requireNonNull(metadataMimeType); return this; } /** - * Set the time {@code interval} between KEEPALIVE frames sent by this client, and the {@code - * maxLifeTime} that this client will allow between KEEPALIVE frames from the server before - * assuming it is dead. + * Set the "Time Between {@code KEEPALIVE} Frames" which is how frequently {@code KEEPALIVE} + * frames should be emitted, and the "Max Lifetime" which is how long to allow between {@code + * KEEPALIVE} frames from the remote end before concluding that connectivity is lost. Both + * settings are specified in the initial {@code SETUP} frame sent to the server. The spec mentions + * the following: * - *

Note that reasonable values for the time interval may vary significantly. For - * server-to-server connections the spec suggests 500ms, while for for mobile-to-server - * connections it suggests 30+ seconds. In addition {@code maxLifeTime} should allow plenty of - * room for multiple missed ticks from the server. + *

    + *
  • For server-to-server connections, a reasonable time interval between client {@code + * KEEPALIVE} frames is 500ms. + *
  • For mobile-to-server connections, the time interval between client {@code KEEPALIVE} + * frames is often > 30,000ms. + *
* - *

By default {@code interval} is set to 20 seconds and {@code maxLifeTime} to 90 seconds. + *

By default these are set to 20 seconds and 90 seconds respectively. * - * @param interval the time between KEEPALIVE frames sent, must be greater than 0. - * @param maxLifeTime the max time between KEEPALIVE frames received, must be greater than 0. + * @param interval how frequently to emit KEEPALIVE frames + * @param maxLifeTime how long to allow between {@code KEEPALIVE} frames from the remote end + * before assuming that connectivity is lost; the value should be generous and allow for + * multiple missed {@code KEEPALIVE} frames. + * @return the same instance for method chaining + * @see SETUP + * Frame */ public RSocketConnector keepAlive(Duration interval, Duration maxLifeTime) { if (!interval.negated().isNegative()) { @@ -134,97 +212,227 @@ public RSocketConnector keepAlive(Duration interval, Duration maxLifeTime) { } /** - * Enables a reconnectable, shared instance of {@code Mono} so every subscriber will - * observe the same RSocket instance up on connection establishment.
- * For example: + * Configure interception at one of the following levels: + * + *

    + *
  • Transport level + *
  • At the level of accepting new connections + *
  • Performing requests + *
  • Responding to requests + *
+ * + * @param configurer a configurer to customize interception with. + * @return the same instance for method chaining + */ + public RSocketConnector interceptors(Consumer configurer) { + configurer.accept(this.interceptors); + return this; + } + + /** + * Configure a client-side {@link SocketAcceptor} for responding to requests from the server. + * + *

A full-form example with access to the {@code SETUP} frame and the "sending" RSocket (the + * same as the one returned from {@link #connect(ClientTransport)}): * *

{@code
-   * Mono sharedRSocketMono =
-   *   RSocketConnector.create()
-   *           .reconnect(Retry.fixedDelay(3, Duration.ofSeconds(1)))
-   *           .connect(transport);
+   * Mono rsocketMono =
+   *     RSocketConnector.create()
+   *             .acceptor((setup, sendingRSocket) -> Mono.just(new RSocket() {...}))
+   *             .connect(transport);
+   * }
* - * RSocket r1 = sharedRSocketMono.block(); - * RSocket r2 = sharedRSocketMono.block(); + *

A shortcut example with just the handling RSocket: * - * assert r1 == r2; + *

{@code
+   * Mono rsocketMono =
+   *     RSocketConnector.create()
+   *             .acceptor(SocketAcceptor.with(new RSocket() {...})))
+   *             .connect(transport);
+   * }
* + *

A shortcut example handling only request-response: + * + *

{@code
+   * Mono rsocketMono =
+   *     RSocketConnector.create()
+   *             .acceptor(SocketAcceptor.forRequestResponse(payload -> ...))
+   *             .connect(transport);
    * }
* - * Apart of the shared behavior, if the connection is lost, the same {@code Mono} - * instance will transparently re-establish the connection for subsequent subscribers.
- * For example: + *

By default, {@code new RSocket(){}} is used which rejects all requests from the server with + * {@link UnsupportedOperationException}. + * + * @param acceptor the acceptor to use for responding to server requests + * @return the same instance for method chaining + */ + public RSocketConnector acceptor(SocketAcceptor acceptor) { + this.acceptor = acceptor; + return this; + } + + /** + * When this is enabled, the connect methods of this class return a special {@code Mono} + * that maintains a single, shared {@code RSocket} for all subscribers: * *

{@code
-   * Mono sharedRSocketMono =
+   * Mono rsocketMono =
    *   RSocketConnector.create()
    *           .reconnect(Retry.fixedDelay(3, Duration.ofSeconds(1)))
    *           .connect(transport);
    *
-   *  RSocket r1 = sharedRSocketMono.block();
-   *  RSocket r2 = sharedRSocketMono.block();
+   *  RSocket r1 = rsocketMono.block();
+   *  RSocket r2 = rsocketMono.block();
    *
    *  assert r1 == r2;
+   * }
* - * r1.dispose() + *

The {@code RSocket} remains cached until the connection is lost and after that, new attempts + * to subscribe or re-subscribe trigger a reconnect and result in a new shared {@code RSocket}: * - * assert r2.isDisposed() + *

{@code
+   * Mono rsocketMono =
+   *   RSocketConnector.create()
+   *           .reconnect(Retry.fixedDelay(3, Duration.ofSeconds(1)))
+   *           .connect(transport);
+   *
+   *  RSocket r1 = rsocketMono.block();
+   *  RSocket r2 = rsocketMono.block();
    *
-   *  RSocket r3 = sharedRSocketMono.block();
-   *  RSocket r4 = sharedRSocketMono.block();
+   *  r1.dispose();
    *
+   *  RSocket r3 = rsocketMono.block();
+   *  RSocket r4 = rsocketMono.block();
+   *
+   *  assert r1 == r2;
+   *  assert r3 == r4;
    *  assert r1 != r3;
-   *  assert r4 == r3;
    *
    * }
* - * Note, having reconnect() enabled does not eliminate the need to accompany each - * individual request with the corresponding retry logic.
- * For example: + *

Downstream subscribers for individual requests still need their own retry logic to determine + * if or when failed requests should be retried which in turn triggers the shared reconnect: * *

{@code
-   * Mono sharedRSocketMono =
+   * Mono rocketMono =
    *   RSocketConnector.create()
    *           .reconnect(Retry.fixedDelay(3, Duration.ofSeconds(1)))
    *           .connect(transport);
    *
-   *  sharedRSocket.flatMap(rSocket -> rSocket.requestResponse(...))
-   *               .retryWhen(ownRetry)
-   *               .subscribe()
-   *
+   *  rsocketMono.flatMap(rsocket -> rsocket.requestResponse(...))
+   *           .retryWhen(Retry.fixedDelay(1, Duration.ofSeconds(5)))
+   *           .subscribe()
    * }
* - * @param retrySpec a retry factory applied for {@link Mono#retryWhen(Retry)} - * @return a shared instance of {@code Mono}. + *

Note: this feature is mutually exclusive with {@link #resume(Resume)}. If + * both are enabled, "resume" takes precedence. Consider using "reconnect" when the server does + * not have "resume" enabled or supported, or when you don't need to incur the overhead of saving + * in-flight frames to be potentially replayed after a reconnect. + * + *

By default this is not enabled in which case a new connection is obtained per subscriber. + * + * @param retry a retry spec that declares the rules for reconnecting + * @return the same instance for method chaining */ - public RSocketConnector reconnect(Retry retrySpec) { - this.retrySpec = Objects.requireNonNull(retrySpec); + public RSocketConnector reconnect(Retry retry) { + this.retrySpec = Objects.requireNonNull(retry); return this; } + /** + * Enables the Resume capability of the RSocket protocol where if the client gets disconnected, + * the connection is re-acquired and any interrupted streams are resumed automatically. For this + * to work the server must also support and have the Resume capability enabled. + * + *

See {@link Resume} for settings to customize the Resume capability. + * + *

Note: this feature is mutually exclusive with {@link #reconnect(Retry)}. If + * both are enabled, "resume" takes precedence. Consider using "reconnect" when the server does + * not have "resume" enabled or supported, or when you don't need to incur the overhead of saving + * in-flight frames to be potentially replayed after a reconnect. + * + *

By default this is not enabled. + * + * @param resume configuration for the Resume capability + * @return the same instance for method chaining + * @see Resuming + * Operation + */ public RSocketConnector resume(Resume resume) { this.resume = resume; return this; } + /** + * Enables the Lease feature of the RSocket protocol where the number of requests that can be + * performed from either side are rationed via {@code LEASE} frames from the responder side. + * + *

Example usage: + * + *

{@code
+   * Mono rocketMono =
+   *         RSocketConnector.create().lease(Leases::new).connect(transport);
+   * }
+ * + *

By default this is not enabled. + * + * @param supplier supplier for a {@link Leases} + * @return the same instance for method chaining Lease + * Semantics + */ public RSocketConnector lease(Supplier> supplier) { this.leasesSupplier = supplier; return this; } + /** + * When this is set, frames larger than the given maximum transmission unit (mtu) size value are + * broken down into fragments to fit that size. + * + *

By default this is not set in which case payloads are sent whole up to the maximum frame + * size of 16,777,215 bytes. + * + * @param mtu the threshold size for fragmentation, must be no less than 64 + * @return the same instance for method chaining + * @see Fragmentation + * and Reassembly + */ public RSocketConnector fragment(int mtu) { - if (mtu > 0 && mtu < MIN_MTU_SIZE || mtu < 0) { + if (mtu > 0 && mtu < FragmentationDuplexConnection.MIN_MTU_SIZE || mtu < 0) { String msg = - String.format("smallest allowed mtu size is %d bytes, provided: %d", MIN_MTU_SIZE, mtu); + String.format( + "The smallest allowed mtu size is %d bytes, provided: %d", + FragmentationDuplexConnection.MIN_MTU_SIZE, mtu); throw new IllegalArgumentException(msg); } this.mtu = mtu; return this; } - public RSocketConnector payloadDecoder(PayloadDecoder payloadDecoder) { - Objects.requireNonNull(payloadDecoder); - this.payloadDecoder = payloadDecoder; + /** + * Configure the {@code PayloadDecoder} used to create {@link Payload}'s from incoming raw frame + * buffers. The following decoders are available: + * + *

    + *
  • {@link PayloadDecoder#DEFAULT} -- the data and metadata are independent copies of the + * underlying frame {@link ByteBuf} + *
  • {@link PayloadDecoder#ZERO_COPY} -- the data and metadata are retained slices of the + * underlying {@link ByteBuf}. That's more efficient but requires careful tracking and + * {@link Payload#release() release} of the payload when no longer needed. + *
+ * + *

By default this is set to {@link PayloadDecoder#DEFAULT} in which case data and metadata are + * copied and do not need to be tracked and released. + * + * @param decoder the decoder to use + * @return the same instance for method chaining + */ + public RSocketConnector payloadDecoder(PayloadDecoder decoder) { + Objects.requireNonNull(decoder); + this.payloadDecoder = decoder; return this; } @@ -239,10 +447,38 @@ public RSocketConnector errorConsumer(Consumer errorConsumer) { return this; } + /** + * The final step to connect with the transport to use as input and the resulting {@code + * Mono} as output. Each subscriber to the returned {@code Mono} starts a new connection + * if neither {@link #reconnect(Retry) reconnect} nor {@link #resume(Resume)} are enabled. + * + *

The following transports are available (via additional RSocket Java modules): + * + *

    + *
  • {@link io.rsocket.transport.netty.client.TcpClientTransport TcpClientTransport} via + * {@code rsocket-transport-netty}. + *
  • {@link io.rsocket.transport.netty.client.WebsocketClientTransport + * WebsocketClientTransport} via {@code rsocket-transport-netty}. + *
  • {@link io.rsocket.transport.local.LocalClientTransport LocalClientTransport} via {@code + * rsocket-transport-local} + *
+ * + * @param transport the transport of choice to connect with + * @return a {@code Mono} with the connected RSocket + */ public Mono connect(ClientTransport transport) { return connect(() -> transport); } + /** + * Variant of {@link #connect(ClientTransport)} with a {@link Supplier} for the {@code + * ClientTransport}. + * + *

// TODO: when to use? + * + * @param transportSupplier supplier for the transport to connect with + * @return a {@code Mono} with the connected RSocket + */ public Mono connect(Supplier transportSupplier) { Mono connectionMono = Mono.fromSupplier(transportSupplier).flatMap(t -> t.connect(mtu)); @@ -310,6 +546,9 @@ public Mono connect(Supplier transportSupplier) { dataMimeType, setupPayload); + SocketAcceptor acceptor = + this.acceptor != null ? this.acceptor : SocketAcceptor.with(new RSocket() {}); + ConnectionSetupPayload setup = new DefaultConnectionSetupPayload(setupFrame); return interceptors diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java index d5d8cee0f..036900be1 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java @@ -20,10 +20,12 @@ import io.rsocket.Closeable; import io.rsocket.ConnectionSetupPayload; import io.rsocket.DuplexConnection; +import io.rsocket.Payload; import io.rsocket.RSocket; import io.rsocket.SocketAcceptor; import io.rsocket.exceptions.InvalidSetupException; import io.rsocket.exceptions.RejectedSetupException; +import io.rsocket.fragmentation.FragmentationDuplexConnection; import io.rsocket.frame.FrameHeaderFlyweight; import io.rsocket.frame.SetupFrameFlyweight; import io.rsocket.frame.decoder.PayloadDecoder; @@ -41,64 +43,207 @@ import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; +/** + * The main class for starting an RSocket server. + * + *

For example: + * + *

{@code
+ * CloseableChannel closeable =
+ *         RSocketServer.create(SocketAcceptor.with(new RSocket() {...}))
+ *                 .bind(TcpServerTransport.create("localhost", 7000))
+ *                 .block();
+ * }
+ */ public final class RSocketServer { private static final String SERVER_TAG = "server"; - private static final int MIN_MTU_SIZE = 64; private SocketAcceptor acceptor = SocketAcceptor.with(new RSocket() {}); private InitializingInterceptorRegistry interceptors = new InitializingInterceptorRegistry(); - private int mtu = 0; private Resume resume; private Supplier> leasesSupplier = null; - private Consumer errorConsumer = ex -> {}; + private int mtu = 0; private PayloadDecoder payloadDecoder = PayloadDecoder.DEFAULT; + private Consumer errorConsumer = ex -> {}; + private RSocketServer() {} + /** Static factory method to create an {@code RSocketServer}. */ public static RSocketServer create() { return new RSocketServer(); } + /** + * Static factory method to create an {@code RSocketServer} instance with the given {@code + * SocketAcceptor}. Effectively a shortcut for: + * + *
+   * RSocketServer.create().acceptor(...);
+   * 
+ * + * @param acceptor the acceptor to handle connections with + * @return the same instance for method chaining + * @see #acceptor(SocketAcceptor) + */ public static RSocketServer create(SocketAcceptor acceptor) { return RSocketServer.create().acceptor(acceptor); } + /** + * Set the acceptor to handle incoming connections and handle requests. + * + *

An example with access to the {@code SETUP} frame and sending RSocket for performing + * requests back to the client if needed: + * + *

{@code
+   * RSocketServer.create((setup, sendingRSocket) -> Mono.just(new RSocket() {...}))
+   *         .bind(TcpServerTransport.create("localhost", 7000))
+   *         .subscribe();
+   * }
+ * + *

A shortcut to provide the handling RSocket only: + * + *

{@code
+   * RSocketServer.create(SocketAcceptor.with(new RSocket() {...}))
+   *         .bind(TcpServerTransport.create("localhost", 7000))
+   *         .subscribe();
+   * }
+ * + *

A shortcut to handle request-response interactions only: + * + *

{@code
+   * RSocketServer.create(SocketAcceptor.forRequestResponse(payload -> ...))
+   *         .bind(TcpServerTransport.create("localhost", 7000))
+   *         .subscribe();
+   * }
+ * + *

By default, {@code new RSocket(){}} is used for handling which rejects requests from the + * client with {@link UnsupportedOperationException}. + * + * @param acceptor the acceptor to handle incoming connections and requests with + * @return the same instance for method chaining + */ public RSocketServer acceptor(SocketAcceptor acceptor) { Objects.requireNonNull(acceptor); this.acceptor = acceptor; return this; } - public RSocketServer interceptors(Consumer consumer) { - consumer.accept(this.interceptors); - return this; - } - - public RSocketServer fragment(int mtu) { - if (mtu > 0 && mtu < MIN_MTU_SIZE || mtu < 0) { - String msg = - String.format("smallest allowed mtu size is %d bytes, provided: %d", MIN_MTU_SIZE, mtu); - throw new IllegalArgumentException(msg); - } - this.mtu = mtu; + /** + * Configure interception at one of the following levels: + * + *

    + *
  • Transport level + *
  • At the level of accepting new connections + *
  • Performing requests + *
  • Responding to requests + *
+ * + * @param configurer a configurer to customize interception with. + * @return the same instance for method chaining + */ + public RSocketServer interceptors(Consumer configurer) { + configurer.accept(this.interceptors); return this; } + /** + * Enables the Resume capability of the RSocket protocol where if the client gets disconnected, + * the connection is re-acquired and any interrupted streams are transparently resumed. For this + * to work clients must also support and request to enable this when connecting. + * + *

Use the {@link Resume} argument to customize the Resume session duration, storage, retry + * logic, and others. + * + *

By default this is not enabled. + * + * @param resume configuration for the Resume capability + * @return the same instance for method chaining + * @see Resuming + * Operation + */ public RSocketServer resume(Resume resume) { this.resume = resume; return this; } + /** + * Enables the Lease feature of the RSocket protocol where the number of requests that can be + * performed from either side are rationed via {@code LEASE} frames from the responder side. For + * this to work clients must also support and request to enable this when connecting. + * + *

Example usage: + * + *

{@code
+   * RSocketServer.create(SocketAcceptor.with(new RSocket() {...}))
+   *         .lease(Leases::new)
+   *         .bind(TcpServerTransport.create("localhost", 7000))
+   *         .subscribe();
+   * }
+ * + *

By default this is not enabled. + * + * @param supplier supplier for a {@link Leases} + * @return the same instance for method chaining + * @return the same instance for method chaining Lease + * Semantics + */ public RSocketServer lease(Supplier> supplier) { this.leasesSupplier = supplier; return this; } - public RSocketServer payloadDecoder(PayloadDecoder payloadDecoder) { - Objects.requireNonNull(payloadDecoder); - this.payloadDecoder = payloadDecoder; + /** + * When this is set, frames larger than the given maximum transmission unit (mtu) size value are + * fragmented. + * + *

By default this is not set in which case payloads are sent whole up to the maximum frame + * size of 16,777,215 bytes. + * + * @param mtu the threshold size for fragmentation, must be no less than 64 + * @return the same instance for method chaining + * @see Fragmentation + * and Reassembly + */ + public RSocketServer fragment(int mtu) { + if (mtu > 0 && mtu < FragmentationDuplexConnection.MIN_MTU_SIZE || mtu < 0) { + String msg = + String.format( + "The smallest allowed mtu size is %d bytes, provided: %d", + FragmentationDuplexConnection.MIN_MTU_SIZE, mtu); + throw new IllegalArgumentException(msg); + } + this.mtu = mtu; + return this; + } + + /** + * Configure the {@code PayloadDecoder} used to create {@link Payload}'s from incoming raw frame + * buffers. The following decoders are available: + * + *

    + *
  • {@link PayloadDecoder#DEFAULT} -- the data and metadata are independent copies of the + * underlying frame {@link ByteBuf} + *
  • {@link PayloadDecoder#ZERO_COPY} -- the data and metadata are retained slices of the + * underlying {@link ByteBuf}. That's more efficient but requires careful tracking and + * {@link Payload#release() release} of the payload when no longer needed. + *
+ * + *

By default this is set to {@link PayloadDecoder#DEFAULT} in which case data and metadata are + * copied and do not need to be tracked and released. + * + * @param decoder the decoder to use + * @return the same instance for method chaining + */ + public RSocketServer payloadDecoder(PayloadDecoder decoder) { + Objects.requireNonNull(decoder); + this.payloadDecoder = decoder; return this; } @@ -112,17 +257,25 @@ public RSocketServer errorConsumer(Consumer errorConsumer) { return this; } - public ServerTransport.ConnectionAcceptor asConnectionAcceptor() { - return new ServerTransport.ConnectionAcceptor() { - private final ServerSetup serverSetup = serverSetup(); - - @Override - public Mono apply(DuplexConnection connection) { - return acceptor(serverSetup, connection); - } - }; - } - + /** + * Start the server on the given transport. + * + *

The following transports are available from additional RSocket Java modules: + * + *

    + *
  • {@link io.rsocket.transport.netty.client.TcpServerTransport TcpServerTransport} via + * {@code rsocket-transport-netty}. + *
  • {@link io.rsocket.transport.netty.client.WebsocketServerTransport + * WebsocketServerTransport} via {@code rsocket-transport-netty}. + *
  • {@link io.rsocket.transport.local.LocalServerTransport LocalServerTransport} via {@code + * rsocket-transport-local} + *
+ * + * @param transport the transport of choice to connect with + * @param the type of {@code Closeable} for the given transport + * @return a {@code Mono} with a {@code Closeable} that can be used to obtain information about + * the server, stop it, or be notified of when it is stopped. + */ public Mono bind(ServerTransport transport) { return Mono.defer( new Supplier>() { @@ -137,6 +290,23 @@ public Mono get() { }); } + /** + * An alternative to {@link #bind(ServerTransport)} that is useful for installing RSocket on a + * server that is started independently. + * + * @see io.rsocket.examples.transport.ws.WebSocketHeadersSample + */ + public ServerTransport.ConnectionAcceptor asConnectionAcceptor() { + return new ServerTransport.ConnectionAcceptor() { + private final ServerSetup serverSetup = serverSetup(); + + @Override + public Mono apply(DuplexConnection connection) { + return acceptor(serverSetup, connection); + } + }; + } + private Mono acceptor(ServerSetup serverSetup, DuplexConnection connection) { ClientServerInputMultiplexer multiplexer = new ClientServerInputMultiplexer(connection, interceptors, false); diff --git a/rsocket-core/src/main/java/io/rsocket/core/Resume.java b/rsocket-core/src/main/java/io/rsocket/core/Resume.java index aedcc9e5e..04221154f 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/Resume.java +++ b/rsocket-core/src/main/java/io/rsocket/core/Resume.java @@ -20,20 +20,29 @@ import io.rsocket.resume.InMemoryResumableFramesStore; import io.rsocket.resume.ResumableFramesStore; import java.time.Duration; +import java.util.Objects; import java.util.function.Function; import java.util.function.Supplier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import reactor.util.retry.Retry; +/** + * Simple holder of configuration settings for the RSocket Resume capability. This can be used to + * configure an {@link RSocketConnector} or an {@link RSocketServer} except for {@link + * #retry(Retry)} and {@link #token(Supplier)} which apply only to the client side. + */ public class Resume { private static final Logger logger = LoggerFactory.getLogger(Resume.class); private Duration sessionDuration = Duration.ofMinutes(2); - private Duration streamTimeout = Duration.ofSeconds(10); + + /* Storage */ private boolean cleanupStoreOnKeepAlive; private Function storeFactory; + private Duration streamTimeout = Duration.ofSeconds(10); + /* Client only */ private Supplier tokenSupplier = ResumeFrameFlyweight::generateResumeToken; private Retry retry = Retry.backoff(Long.MAX_VALUE, Duration.ofSeconds(1)) @@ -43,43 +52,105 @@ public class Resume { public Resume() {} + /** + * The maximum time for a client to keep trying to reconnect. During this time client and server + * continue to store unsent frames to keep the session warm and ready to resume. + * + *

By default this is set to 2 minutes. + * + * @param sessionDuration the max duration for a session + * @return the same instance for method chaining + */ public Resume sessionDuration(Duration sessionDuration) { - this.sessionDuration = sessionDuration; - return this; - } - - public Resume streamTimeout(Duration streamTimeout) { - this.streamTimeout = streamTimeout; + this.sessionDuration = Objects.requireNonNull(sessionDuration); return this; } + /** + * When this property is enabled, hints from {@code KEEPALIVE} frames about how much data has been + * received by the other side, is used to proactively clean frames from the {@link + * #storeFactory(Function) store}. + * + *

By default this is set to {@code false} in which case information from {@code KEEPALIVE} is + * ignored and old frames from the store are removed only when the store runs out of space. + * + * @return the same instance for method chaining + */ public Resume cleanupStoreOnKeepAlive() { this.cleanupStoreOnKeepAlive = true; return this; } + /** + * Configure a factory to create the storage for buffering (or persisting) a window of frames that + * may need to be sent again to resume after a dropped connection. + * + *

By default {@link InMemoryResumableFramesStore} is used with its cache size set to 100,000 + * bytes. When the cache fills up, the oldest frames are gradually removed to create space for new + * ones. + * + * @param storeFactory the factory to use to create the store + * @return the same instance for method chaining + */ public Resume storeFactory( Function storeFactory) { this.storeFactory = storeFactory; return this; } - public Resume token(Supplier supplier) { - this.tokenSupplier = supplier; + /** + * A {@link reactor.core.publisher.Flux#timeout(Duration) timeout} value to apply to the resumed + * session stream obtained from the {@link #storeFactory(Function) store} after a reconnect. The + * resume stream must not take longer than the specified time to emit each frame. + * + *

By default this is set to 10 seconds. + * + * @param streamTimeout the timeout value for resuming a session stream + * @return the same instance for method chaining + */ + public Resume streamTimeout(Duration streamTimeout) { + this.streamTimeout = Objects.requireNonNull(streamTimeout); return this; } + /** + * Configure the logic for reconnecting. This setting is for use with {@link + * RSocketConnector#resume(Resume)} on the client side only. + * + *

By default this is set to: + * + *

{@code
+   * Retry.backoff(Long.MAX_VALUE, Duration.ofSeconds(1))
+   *     .maxBackoff(Duration.ofSeconds(16))
+   *     .jitter(1.0)
+   * }
+ * + * @param retry the {@code Retry} spec to use when attempting to reconnect + * @return the same instance for method chaining + */ public Resume retry(Retry retry) { this.retry = retry; return this; } - Duration getSessionDuration() { - return sessionDuration; + /** + * Customize the generation of the resume identification token used to resume. This setting is for + * use with {@link RSocketConnector#resume(Resume)} on the client side only. + * + *

By default this is {@code ResumeFrameFlyweight::generateResumeToken}. + * + * @param supplier a custom generator for a resume identification token + * @return the same instance for method chaining + */ + public Resume token(Supplier supplier) { + this.tokenSupplier = supplier; + return this; } - Duration getStreamTimeout() { - return streamTimeout; + // Package private accessors + + Duration getSessionDuration() { + return sessionDuration; } boolean isCleanupStoreOnKeepAlive() { @@ -92,11 +163,15 @@ boolean isCleanupStoreOnKeepAlive() { : token -> new InMemoryResumableFramesStore(tag, 100_000); } - Supplier getTokenSupplier() { - return tokenSupplier; + Duration getStreamTimeout() { + return streamTimeout; } Retry getRetry() { return retry; } + + Supplier getTokenSupplier() { + return tokenSupplier; + } } diff --git a/rsocket-core/src/main/java/io/rsocket/fragmentation/FragmentationDuplexConnection.java b/rsocket-core/src/main/java/io/rsocket/fragmentation/FragmentationDuplexConnection.java index 316643e10..24b360755 100644 --- a/rsocket-core/src/main/java/io/rsocket/fragmentation/FragmentationDuplexConnection.java +++ b/rsocket-core/src/main/java/io/rsocket/fragmentation/FragmentationDuplexConnection.java @@ -41,7 +41,7 @@ */ public final class FragmentationDuplexConnection extends ReassemblyDuplexConnection implements DuplexConnection { - private static final int MIN_MTU_SIZE = 64; + public static final int MIN_MTU_SIZE = 64; private static final Logger logger = LoggerFactory.getLogger(FragmentationDuplexConnection.class); private final DuplexConnection delegate; private final int mtu; diff --git a/rsocket-core/src/test/java/io/rsocket/core/RSocketServerFragmentationTest.java b/rsocket-core/src/test/java/io/rsocket/core/RSocketServerFragmentationTest.java index 9d105a8c9..073ebfd06 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/RSocketServerFragmentationTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/RSocketServerFragmentationTest.java @@ -11,7 +11,7 @@ public class RSocketServerFragmentationTest { public void serverErrorsWithEnabledFragmentationOnInsufficientMtu() { Assertions.assertThatIllegalArgumentException() .isThrownBy(() -> RSocketServer.create().fragment(2)) - .withMessage("smallest allowed mtu size is 64 bytes, provided: 2"); + .withMessage("The smallest allowed mtu size is 64 bytes, provided: 2"); } @Test @@ -28,12 +28,12 @@ public void serverSucceedsWithDisabledFragmentation() { public void clientErrorsWithEnabledFragmentationOnInsufficientMtu() { Assertions.assertThatIllegalArgumentException() .isThrownBy(() -> RSocketConnector.create().fragment(2)) - .withMessage("smallest allowed mtu size is 64 bytes, provided: 2"); + .withMessage("The smallest allowed mtu size is 64 bytes, provided: 2"); } @Test public void clientSucceedsWithEnabledFragmentationOnSufficientMtu() { - RSocketConnector.create().fragment(100).connect(TestClientTransport::new).block(); + RSocketConnector.create().fragment(100).connect(new TestClientTransport()).block(); } @Test From c9a4f064ca1fe8fb06b67f7ac09ba2777bbb5634 Mon Sep 17 00:00:00 2001 From: Oleh Dokuka Date: Mon, 4 May 2020 15:32:20 +0300 Subject: [PATCH 14/25] relaxed stream id supplement (#814) --- .../java/io/rsocket/core/StreamIdSupplier.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/rsocket-core/src/main/java/io/rsocket/core/StreamIdSupplier.java b/rsocket-core/src/main/java/io/rsocket/core/StreamIdSupplier.java index 70734b8c0..7f4d7b7b3 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/StreamIdSupplier.java +++ b/rsocket-core/src/main/java/io/rsocket/core/StreamIdSupplier.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2018 the original author or authors. + * Copyright 2015-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +16,11 @@ package io.rsocket.core; import io.netty.util.collection.IntObjectMap; -import java.util.concurrent.atomic.AtomicLongFieldUpdater; final class StreamIdSupplier { private static final int MASK = 0x7FFFFFFF; - private static final AtomicLongFieldUpdater STREAM_ID = - AtomicLongFieldUpdater.newUpdater(StreamIdSupplier.class, "streamId"); - private volatile long streamId; + private long streamId; // Visible for testing StreamIdSupplier(int streamId) { @@ -38,10 +35,18 @@ static StreamIdSupplier serverSupplier() { return new StreamIdSupplier(0); } + /** + * This methods provides new stream id and ensures there is no intersections with already running + * streams. This methods is not thread-safe. + * + * @param streamIds currently running streams store + * @return next stream id + */ int nextStreamId(IntObjectMap streamIds) { int streamId; do { - streamId = (int) STREAM_ID.addAndGet(this, 2) & MASK; + this.streamId += 2; + streamId = (int) (this.streamId & MASK); } while (streamId == 0 || streamIds.containsKey(streamId)); return streamId; } From be382d7dba2464ae7421bc7b720f70aab71d518c Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Wed, 6 May 2020 18:26:15 +0100 Subject: [PATCH 15/25] Add missing package-infos and Javadoc in plugins package (#817) --- .../io/rsocket/core/RSocketConnector.java | 4 +- .../java/io/rsocket/core/RSocketServer.java | 4 +- .../java/io/rsocket/core/package-info.java | 8 ++- .../io/rsocket/exceptions/package-info.java | 4 +- .../java/io/rsocket/frame/package-info.java | 21 +++++++ .../io/rsocket/keepalive/package-info.java | 19 ++++++ .../java/io/rsocket/lease/package-info.java | 9 ++- .../io/rsocket/metadata/package-info.java | 22 +++++++ .../main/java/io/rsocket/package-info.java | 11 +++- .../plugins/DuplexConnectionInterceptor.java | 8 ++- .../InitializingInterceptorRegistry.java | 4 ++ .../rsocket/plugins/InterceptorRegistry.java | 63 +++++++++++++++---- .../rsocket/plugins/RSocketInterceptor.java | 9 ++- .../plugins/SocketAcceptorInterceptor.java | 6 +- .../java/io/rsocket/plugins/package-info.java | 18 ++++++ .../java/io/rsocket/resume/package-info.java | 7 +++ .../io/rsocket/transport/package-info.java | 3 +- .../java/io/rsocket/util/package-info.java | 3 +- 18 files changed, 191 insertions(+), 32 deletions(-) create mode 100644 rsocket-core/src/main/java/io/rsocket/frame/package-info.java create mode 100644 rsocket-core/src/main/java/io/rsocket/keepalive/package-info.java create mode 100644 rsocket-core/src/main/java/io/rsocket/metadata/package-info.java create mode 100644 rsocket-core/src/main/java/io/rsocket/plugins/package-info.java diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java index 3d9345c4b..45d16a665 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java @@ -378,8 +378,8 @@ public RSocketConnector resume(Resume resume) { *

By default this is not enabled. * * @param supplier supplier for a {@link Leases} - * @return the same instance for method chaining Lease + * @return the same instance for method chaining + * @see Lease * Semantics */ public RSocketConnector lease(Supplier> supplier) { diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java index 036900be1..5960e33d4 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java @@ -189,8 +189,8 @@ public RSocketServer resume(Resume resume) { * * @param supplier supplier for a {@link Leases} * @return the same instance for method chaining - * @return the same instance for method chaining Lease + * @return the same instance for method chaining + * @see Lease * Semantics */ public RSocketServer lease(Supplier> supplier) { diff --git a/rsocket-core/src/main/java/io/rsocket/core/package-info.java b/rsocket-core/src/main/java/io/rsocket/core/package-info.java index a70bb3b16..29db3f205 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/package-info.java +++ b/rsocket-core/src/main/java/io/rsocket/core/package-info.java @@ -15,8 +15,12 @@ */ /** - * Contains core RSocket protocol, client and server implementation classes, including factories to - * create and configure them. + * Contains {@link io.rsocket.core.RSocketConnector RSocketConnector} and {@link + * io.rsocket.core.RSocketServer RSocketServer}, the main classes for connecting to or starting an + * RSocket server. + * + *

This package also contains a package private classes that implement support for the main + * RSocket interactions. */ @NonNullApi package io.rsocket.core; diff --git a/rsocket-core/src/main/java/io/rsocket/exceptions/package-info.java b/rsocket-core/src/main/java/io/rsocket/exceptions/package-info.java index babf8194e..969aedded 100644 --- a/rsocket-core/src/main/java/io/rsocket/exceptions/package-info.java +++ b/rsocket-core/src/main/java/io/rsocket/exceptions/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2018 the original author or authors. + * Copyright 2015-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,7 @@ */ /** - * The hierarchy of exceptions that can be returned by the API + * A hierarchy of exceptions that represent RSocket protocol error codes. * * @see Error * Codes diff --git a/rsocket-core/src/main/java/io/rsocket/frame/package-info.java b/rsocket-core/src/main/java/io/rsocket/frame/package-info.java new file mode 100644 index 000000000..1d02ebca0 --- /dev/null +++ b/rsocket-core/src/main/java/io/rsocket/frame/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2015-2020 the original author or authors. + * + * Licensed 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. + */ + +/** + * Support for encoding and decoding of RSocket frames to and from {@link io.rsocket.Payload + * Payload}. + */ +package io.rsocket.frame; diff --git a/rsocket-core/src/main/java/io/rsocket/keepalive/package-info.java b/rsocket-core/src/main/java/io/rsocket/keepalive/package-info.java new file mode 100644 index 000000000..ce8a2f3fb --- /dev/null +++ b/rsocket-core/src/main/java/io/rsocket/keepalive/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2015-2020 the original author or authors. + * + * Licensed 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. + */ + +/** Support classes for sending and keeping track of KEEPALIVE frames from the remote. */ +@javax.annotation.ParametersAreNonnullByDefault +package io.rsocket.keepalive; diff --git a/rsocket-core/src/main/java/io/rsocket/lease/package-info.java b/rsocket-core/src/main/java/io/rsocket/lease/package-info.java index 6700c10d9..ce1956628 100644 --- a/rsocket-core/src/main/java/io/rsocket/lease/package-info.java +++ b/rsocket-core/src/main/java/io/rsocket/lease/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2018 the original author or authors. + * Copyright 2015-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,5 +14,12 @@ * limitations under the License. */ +/** + * Contains support classes for the Lease feature of the RSocket protocol. + * + * @see Resuming + * Operation + */ @javax.annotation.ParametersAreNonnullByDefault package io.rsocket.lease; diff --git a/rsocket-core/src/main/java/io/rsocket/metadata/package-info.java b/rsocket-core/src/main/java/io/rsocket/metadata/package-info.java new file mode 100644 index 000000000..b1bc45ff0 --- /dev/null +++ b/rsocket-core/src/main/java/io/rsocket/metadata/package-info.java @@ -0,0 +1,22 @@ +/* + * Copyright 2015-2020 the original author or authors. + * + * Licensed 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. + */ + +/** + * Contains implementations of RSocket protocol extensions related + * to the use of metadata. + */ +package io.rsocket.metadata; diff --git a/rsocket-core/src/main/java/io/rsocket/package-info.java b/rsocket-core/src/main/java/io/rsocket/package-info.java index 243c1ab52..878a56301 100644 --- a/rsocket-core/src/main/java/io/rsocket/package-info.java +++ b/rsocket-core/src/main/java/io/rsocket/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2018 the original author or authors. + * Copyright 2015-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,4 +14,13 @@ * limitations under the License. */ +/** + * Contains key contracts of the RSocket programming model including {@link io.rsocket.RSocket + * RSocket} for performing or handling RSocket interactions, {@link io.rsocket.SocketAcceptor + * SocketAcceptor} for declaring responders, {@link io.rsocket.Payload Payload} for access to the + * content of a payload, and others. + * + *

To connect to or start a server see {@link io.rsocket.core.RSocketConnector RSocketConnector} + * and {@link io.rsocket.core.RSocketServer RSocketServer} in {@link io.rsocket.core}. + */ package io.rsocket; diff --git a/rsocket-core/src/main/java/io/rsocket/plugins/DuplexConnectionInterceptor.java b/rsocket-core/src/main/java/io/rsocket/plugins/DuplexConnectionInterceptor.java index 056ded0cd..6b2a7a71b 100644 --- a/rsocket-core/src/main/java/io/rsocket/plugins/DuplexConnectionInterceptor.java +++ b/rsocket-core/src/main/java/io/rsocket/plugins/DuplexConnectionInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2018 the original author or authors. + * Copyright 2015-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,9 +19,13 @@ import io.rsocket.DuplexConnection; import java.util.function.BiFunction; -/** */ +/** + * Contract to decorate a {@link DuplexConnection} and intercept the sending and receiving of + * RSocket frames at the transport level. + */ public @FunctionalInterface interface DuplexConnectionInterceptor extends BiFunction { + enum Type { SETUP, CLIENT, diff --git a/rsocket-core/src/main/java/io/rsocket/plugins/InitializingInterceptorRegistry.java b/rsocket-core/src/main/java/io/rsocket/plugins/InitializingInterceptorRegistry.java index cf911b954..fc032847c 100644 --- a/rsocket-core/src/main/java/io/rsocket/plugins/InitializingInterceptorRegistry.java +++ b/rsocket-core/src/main/java/io/rsocket/plugins/InitializingInterceptorRegistry.java @@ -19,6 +19,10 @@ import io.rsocket.RSocket; import io.rsocket.SocketAcceptor; +/** + * Extends {@link InterceptorRegistry} with methods for building a chain of registered interceptors. + * This is not intended for direct use by applications. + */ public class InitializingInterceptorRegistry extends InterceptorRegistry { public DuplexConnection initConnection( diff --git a/rsocket-core/src/main/java/io/rsocket/plugins/InterceptorRegistry.java b/rsocket-core/src/main/java/io/rsocket/plugins/InterceptorRegistry.java index f9ee151a8..427fa15ae 100644 --- a/rsocket-core/src/main/java/io/rsocket/plugins/InterceptorRegistry.java +++ b/rsocket-core/src/main/java/io/rsocket/plugins/InterceptorRegistry.java @@ -19,54 +19,87 @@ import java.util.List; import java.util.function.Consumer; +/** + * Provides support for registering interceptors at the following levels: + * + *

    + *
  • {@link #forConnection(DuplexConnectionInterceptor)} -- transport level + *
  • {@link #forSocketAcceptor(SocketAcceptorInterceptor)} -- for accepting new connections + *
  • {@link #forRequester(RSocketInterceptor)} -- for performing of requests + *
  • {@link #forResponder(RSocketInterceptor)} -- for responding to requests + *
+ */ public class InterceptorRegistry { - private List connectionInterceptors = new ArrayList<>(); private List requesterInteceptors = new ArrayList<>(); private List responderInterceptors = new ArrayList<>(); private List socketAcceptorInterceptors = new ArrayList<>(); + private List connectionInterceptors = new ArrayList<>(); - public InterceptorRegistry forConnection(DuplexConnectionInterceptor interceptor) { - connectionInterceptors.add(interceptor); - return this; - } - - public InterceptorRegistry forConnection(Consumer> consumer) { - consumer.accept(connectionInterceptors); - return this; - } - + /** + * Add an {@link RSocketInterceptor} that will decorate the RSocket used for performing requests. + */ public InterceptorRegistry forRequester(RSocketInterceptor interceptor) { requesterInteceptors.add(interceptor); return this; } + /** + * Variant of {@link #forRequester(RSocketInterceptor)} with access to the list of existing + * registrations. + */ public InterceptorRegistry forRequester(Consumer> consumer) { consumer.accept(requesterInteceptors); return this; } + /** + * Add an {@link RSocketInterceptor} that will decorate the RSocket used for resonding to + * requests. + */ public InterceptorRegistry forResponder(RSocketInterceptor interceptor) { responderInterceptors.add(interceptor); return this; } + /** + * Variant of {@link #forResponder(RSocketInterceptor)} with access to the list of existing + * registrations. + */ public InterceptorRegistry forResponder(Consumer> consumer) { consumer.accept(responderInterceptors); return this; } + /** + * Add a {@link SocketAcceptorInterceptor} that will intercept the accepting of new connections. + */ public InterceptorRegistry forSocketAcceptor(SocketAcceptorInterceptor interceptor) { socketAcceptorInterceptors.add(interceptor); return this; } + /** + * Variant of {@link #forSocketAcceptor(SocketAcceptorInterceptor)} with access to the list of + * existing registrations. + */ public InterceptorRegistry forSocketAcceptor(Consumer> consumer) { consumer.accept(socketAcceptorInterceptors); return this; } - List getConnectionInterceptors() { - return connectionInterceptors; + /** Add a {@link DuplexConnectionInterceptor}. */ + public InterceptorRegistry forConnection(DuplexConnectionInterceptor interceptor) { + connectionInterceptors.add(interceptor); + return this; + } + + /** + * Variant of {@link #forConnection(DuplexConnectionInterceptor)} with access to the list of + * existing registrations. + */ + public InterceptorRegistry forConnection(Consumer> consumer) { + consumer.accept(connectionInterceptors); + return this; } List getRequesterInteceptors() { @@ -77,6 +110,10 @@ List getResponderInterceptors() { return responderInterceptors; } + List getConnectionInterceptors() { + return connectionInterceptors; + } + List getSocketAcceptorInterceptors() { return socketAcceptorInterceptors; } diff --git a/rsocket-core/src/main/java/io/rsocket/plugins/RSocketInterceptor.java b/rsocket-core/src/main/java/io/rsocket/plugins/RSocketInterceptor.java index 0bad0faed..0cd4bb8f6 100644 --- a/rsocket-core/src/main/java/io/rsocket/plugins/RSocketInterceptor.java +++ b/rsocket-core/src/main/java/io/rsocket/plugins/RSocketInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2018 the original author or authors. + * Copyright 2015-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,5 +19,10 @@ import io.rsocket.RSocket; import java.util.function.Function; -/** */ +/** + * Contract to decorate an {@link RSocket}, providing a way to intercept interactions. This can be + * applied to a {@link InterceptorRegistry#forRequester(RSocketInterceptor) requester} or {@link + * InterceptorRegistry#forResponder(RSocketInterceptor) responder} {@code RSocket} of a client or + * server. + */ public @FunctionalInterface interface RSocketInterceptor extends Function {} diff --git a/rsocket-core/src/main/java/io/rsocket/plugins/SocketAcceptorInterceptor.java b/rsocket-core/src/main/java/io/rsocket/plugins/SocketAcceptorInterceptor.java index 0cb9d92d2..6dd850ba9 100644 --- a/rsocket-core/src/main/java/io/rsocket/plugins/SocketAcceptorInterceptor.java +++ b/rsocket-core/src/main/java/io/rsocket/plugins/SocketAcceptorInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2019 the original author or authors. + * Copyright 2015-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,8 +22,8 @@ * Contract to decorate a {@link SocketAcceptor}, providing access to connection {@code setup} * information and the ability to also decorate the sockets for requesting and responding. * - *

This can be used as an alternative to individual requester and responder {@link - * RSocketInterceptor} plugins. + *

This could be used as an alternative to registering an individual "requester" {@code + * RSocketInterceptor} and "responder" {@code RSocketInterceptor}. */ public @FunctionalInterface interface SocketAcceptorInterceptor extends Function {} diff --git a/rsocket-core/src/main/java/io/rsocket/plugins/package-info.java b/rsocket-core/src/main/java/io/rsocket/plugins/package-info.java new file mode 100644 index 000000000..743e3a8a4 --- /dev/null +++ b/rsocket-core/src/main/java/io/rsocket/plugins/package-info.java @@ -0,0 +1,18 @@ +/* + * Copyright 2015-2020 the original author or authors. + * + * Licensed 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. + */ + +/** Contracts for interception of transports, connections, and requests in in RSocket Java. */ +package io.rsocket.plugins; diff --git a/rsocket-core/src/main/java/io/rsocket/resume/package-info.java b/rsocket-core/src/main/java/io/rsocket/resume/package-info.java index 57027bee2..aaaa3ee9f 100644 --- a/rsocket-core/src/main/java/io/rsocket/resume/package-info.java +++ b/rsocket-core/src/main/java/io/rsocket/resume/package-info.java @@ -14,5 +14,12 @@ * limitations under the License. */ +/** + * Contains support classes for the RSocket resume capability. + * + * @see Resuming + * Operation + */ @javax.annotation.ParametersAreNonnullByDefault package io.rsocket.resume; diff --git a/rsocket-core/src/main/java/io/rsocket/transport/package-info.java b/rsocket-core/src/main/java/io/rsocket/transport/package-info.java index 86e7c311a..153676324 100644 --- a/rsocket-core/src/main/java/io/rsocket/transport/package-info.java +++ b/rsocket-core/src/main/java/io/rsocket/transport/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2018 the original author or authors. + * Copyright 2015-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,5 +14,6 @@ * limitations under the License. */ +/** Client and server transport contracts for pluggable transports. */ @javax.annotation.ParametersAreNonnullByDefault package io.rsocket.transport; diff --git a/rsocket-core/src/main/java/io/rsocket/util/package-info.java b/rsocket-core/src/main/java/io/rsocket/util/package-info.java index 79123d3b2..e034672f1 100644 --- a/rsocket-core/src/main/java/io/rsocket/util/package-info.java +++ b/rsocket-core/src/main/java/io/rsocket/util/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2018 the original author or authors. + * Copyright 2015-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,5 +14,6 @@ * limitations under the License. */ +/** Shared utility classes and {@link io.rsocket.Payload} implementations. */ @javax.annotation.ParametersAreNonnullByDefault package io.rsocket.util; From 79d2ee66103a73bc130c88d22c75acf1ba54df2a Mon Sep 17 00:00:00 2001 From: Oleh Dokuka Date: Thu, 7 May 2020 10:51:08 +0300 Subject: [PATCH 16/25] Renames Flyweight classes to Codec (#820) --- .../core/DefaultConnectionSetupPayload.java | 26 +- .../rsocket/core/PayloadValidationUtils.java | 18 +- .../io/rsocket/core/RSocketConnector.java | 4 +- .../io/rsocket/core/RSocketRequester.java | 60 ++- .../io/rsocket/core/RSocketResponder.java | 27 +- .../java/io/rsocket/core/RSocketServer.java | 14 +- .../src/main/java/io/rsocket/core/Resume.java | 4 +- .../java/io/rsocket/core/ServerSetup.java | 16 +- .../exceptions/ApplicationErrorException.java | 4 +- .../rsocket/exceptions/CanceledException.java | 4 +- .../exceptions/ConnectionCloseException.java | 4 +- .../exceptions/ConnectionErrorException.java | 4 +- .../exceptions/CustomRSocketException.java | 6 +- .../io/rsocket/exceptions/Exceptions.java | 30 +- .../rsocket/exceptions/InvalidException.java | 4 +- .../exceptions/InvalidSetupException.java | 4 +- .../rsocket/exceptions/RSocketException.java | 4 +- .../rsocket/exceptions/RejectedException.java | 4 +- .../exceptions/RejectedResumeException.java | 4 +- .../exceptions/RejectedSetupException.java | 4 +- .../io/rsocket/exceptions/SetupException.java | 4 +- .../exceptions/UnsupportedSetupException.java | 4 +- .../FragmentationDuplexConnection.java | 14 +- .../fragmentation/FrameFragmenter.java | 66 +-- .../fragmentation/FrameReassembler.java | 44 +- .../ReassemblyDuplexConnection.java | 4 +- ...meFlyweight.java => CancelFrameCodec.java} | 6 +- ...ameFlyweight.java => ErrorFrameCodec.java} | 8 +- .../main/java/io/rsocket/frame/ErrorType.java | 85 ---- .../io/rsocket/frame/ExtensionFrameCodec.java | 66 +++ .../frame/ExtensionFrameFlyweight.java | 66 --- ...Flyweight.java => FragmentationCodec.java} | 4 +- ...dataFlyweight.java => FrameBodyCodec.java} | 4 +- ...erFlyweight.java => FrameHeaderCodec.java} | 4 +- ...thFlyweight.java => FrameLengthCodec.java} | 4 +- .../main/java/io/rsocket/frame/FrameUtil.java | 44 +- .../io/rsocket/frame/GenericFrameCodec.java | 157 +++++++ ...lyweight.java => KeepAliveFrameCodec.java} | 20 +- ...ameFlyweight.java => LeaseFrameCodec.java} | 20 +- ...eight.java => MetadataPushFrameCodec.java} | 8 +- .../io/rsocket/frame/PayloadFrameCodec.java | 54 +++ .../rsocket/frame/PayloadFrameFlyweight.java | 79 ---- .../frame/RequestChannelFrameCodec.java | 67 +++ .../frame/RequestChannelFrameFlyweight.java | 81 ---- .../frame/RequestFireAndForgetFrameCodec.java | 36 ++ .../RequestFireAndForgetFrameFlyweight.java | 63 --- .../io/rsocket/frame/RequestFlyweight.java | 110 ----- ...Flyweight.java => RequestNFrameCodec.java} | 10 +- .../frame/RequestResponseFrameCodec.java | 35 ++ .../frame/RequestResponseFrameFlyweight.java | 62 --- .../frame/RequestStreamFrameCodec.java | 62 +++ .../frame/RequestStreamFrameFlyweight.java | 76 ---- ...meFlyweight.java => ResumeFrameCodec.java} | 22 +- ...Flyweight.java => ResumeOkFrameCodec.java} | 8 +- ...ameFlyweight.java => SetupFrameCodec.java} | 32 +- ...ersionFlyweight.java => VersionCodec.java} | 2 +- .../frame/decoder/DefaultPayloadDecoder.java | 38 +- .../frame/decoder/ZeroCopyPayloadDecoder.java | 38 +- .../ClientServerInputMultiplexer.java | 6 +- .../rsocket/keepalive/KeepAliveSupport.java | 12 +- .../rsocket/lease/RequesterLeaseHandler.java | 8 +- .../rsocket/lease/ResponderLeaseHandler.java | 4 +- .../rsocket/metadata/AuthMetadataCodec.java | 335 +++++++++++++++ .../metadata/CompositeMetadataCodec.java | 385 ++++++++++++++++++ .../metadata/CompositeMetadataFlyweight.java | 169 ++------ .../metadata/TaggingMetadataCodec.java | 76 ++++ .../metadata/TaggingMetadataFlyweight.java | 26 +- .../rsocket/metadata/WellKnownAuthType.java | 121 ++++++ .../security/AuthMetadataFlyweight.java | 175 +------- .../metadata/security/WellKnownAuthType.java | 26 ++ .../rsocket/resume/ClientRSocketSession.java | 12 +- .../resume/ResumableDuplexConnection.java | 4 +- .../rsocket/resume/ServerRSocketSession.java | 16 +- .../core/ConnectionSetupPayloadTest.java | 8 +- .../java/io/rsocket/core/KeepAliveTest.java | 14 +- .../core/PayloadValidationUtilsTest.java | 34 +- .../io/rsocket/core/RSocketLeaseTest.java | 24 +- .../core/RSocketRequesterSubscribersTest.java | 12 +- .../io/rsocket/core/RSocketRequesterTest.java | 112 +++-- .../io/rsocket/core/RSocketResponderTest.java | 90 ++-- .../io/rsocket/core/SetupRejectionTest.java | 16 +- .../io/rsocket/exceptions/ExceptionsTest.java | 28 +- .../FragmentationDuplexConnectionTest.java | 6 +- .../FragmentationIntegrationTest.java | 13 +- .../fragmentation/FrameFragmenterTest.java | 131 +++--- .../fragmentation/FrameReassemblerTest.java | 88 ++-- .../ReassembleDuplexConnectionTest.java | 55 ++- ...ightTest.java => ErrorFrameCodecTest.java} | 6 +- .../frame/ExtensionFrameCodecTest.java | 62 +++ .../frame/ExtensionFrameFlyweightTest.java | 62 --- ...ghtTest.java => FrameHeaderCodecTest.java} | 16 +- ...htTest.java => GenericFrameCodecTest.java} | 96 +++-- .../frame/KeepaliveFrameFlyweightTest.java | 10 +- .../io/rsocket/frame/LeaseFrameCodecTest.java | 42 ++ .../frame/LeaseFrameFlyweightTest.java | 43 -- .../rsocket/frame/PayloadFlyweightTest.java | 39 +- ...tTest.java => RequestNFrameCodecTest.java} | 6 +- ...ghtTest.java => ResumeFrameCodecTest.java} | 13 +- ...tTest.java => ResumeOkFrameCodecTest.java} | 6 +- .../io/rsocket/frame/SetupFrameCodecTest.java | 57 +++ .../frame/SetupFrameFlyweightTest.java | 57 --- ...yweightTest.java => VersionCodecTest.java} | 24 +- .../ClientServerInputMultiplexerTest.java | 14 +- .../MicrometerDuplexConnection.java | 4 +- .../main/java/io/rsocket/test/TestFrames.java | 28 +- .../transport/netty/RSocketLengthCodec.java | 4 +- .../transport/netty/TcpDuplexConnection.java | 6 +- .../client/WebsocketClientTransport.java | 2 +- .../netty/server/WebsocketRouteTransport.java | 2 +- .../server/WebsocketServerTransport.java | 2 +- .../client/WebsocketClientTransportTest.java | 2 +- .../server/WebsocketServerTransportTest.java | 2 +- 112 files changed, 2422 insertions(+), 1941 deletions(-) rename rsocket-core/src/main/java/io/rsocket/frame/{CancelFrameFlyweight.java => CancelFrameCodec.java} (55%) rename rsocket-core/src/main/java/io/rsocket/frame/{ErrorFrameFlyweight.java => ErrorFrameCodec.java} (89%) delete mode 100644 rsocket-core/src/main/java/io/rsocket/frame/ErrorType.java create mode 100644 rsocket-core/src/main/java/io/rsocket/frame/ExtensionFrameCodec.java delete mode 100644 rsocket-core/src/main/java/io/rsocket/frame/ExtensionFrameFlyweight.java rename rsocket-core/src/main/java/io/rsocket/frame/{FragmentationFlyweight.java => FragmentationCodec.java} (80%) rename rsocket-core/src/main/java/io/rsocket/frame/{DataAndMetadataFlyweight.java => FrameBodyCodec.java} (97%) rename rsocket-core/src/main/java/io/rsocket/frame/{FrameHeaderFlyweight.java => FrameHeaderCodec.java} (98%) rename rsocket-core/src/main/java/io/rsocket/frame/{FrameLengthFlyweight.java => FrameLengthCodec.java} (95%) create mode 100644 rsocket-core/src/main/java/io/rsocket/frame/GenericFrameCodec.java rename rsocket-core/src/main/java/io/rsocket/frame/{KeepAliveFrameFlyweight.java => KeepAliveFrameCodec.java} (61%) rename rsocket-core/src/main/java/io/rsocket/frame/{LeaseFrameFlyweight.java => LeaseFrameCodec.java} (74%) rename rsocket-core/src/main/java/io/rsocket/frame/{MetadataPushFrameFlyweight.java => MetadataPushFrameCodec.java} (83%) create mode 100644 rsocket-core/src/main/java/io/rsocket/frame/PayloadFrameCodec.java delete mode 100644 rsocket-core/src/main/java/io/rsocket/frame/PayloadFrameFlyweight.java create mode 100644 rsocket-core/src/main/java/io/rsocket/frame/RequestChannelFrameCodec.java delete mode 100644 rsocket-core/src/main/java/io/rsocket/frame/RequestChannelFrameFlyweight.java create mode 100644 rsocket-core/src/main/java/io/rsocket/frame/RequestFireAndForgetFrameCodec.java delete mode 100644 rsocket-core/src/main/java/io/rsocket/frame/RequestFireAndForgetFrameFlyweight.java delete mode 100644 rsocket-core/src/main/java/io/rsocket/frame/RequestFlyweight.java rename rsocket-core/src/main/java/io/rsocket/frame/{RequestNFrameFlyweight.java => RequestNFrameCodec.java} (68%) create mode 100644 rsocket-core/src/main/java/io/rsocket/frame/RequestResponseFrameCodec.java delete mode 100644 rsocket-core/src/main/java/io/rsocket/frame/RequestResponseFrameFlyweight.java create mode 100644 rsocket-core/src/main/java/io/rsocket/frame/RequestStreamFrameCodec.java delete mode 100644 rsocket-core/src/main/java/io/rsocket/frame/RequestStreamFrameFlyweight.java rename rsocket-core/src/main/java/io/rsocket/frame/{ResumeFrameFlyweight.java => ResumeFrameCodec.java} (79%) rename rsocket-core/src/main/java/io/rsocket/frame/{ResumeOkFrameFlyweight.java => ResumeOkFrameCodec.java} (67%) rename rsocket-core/src/main/java/io/rsocket/frame/{SetupFrameFlyweight.java => SetupFrameCodec.java} (83%) rename rsocket-core/src/main/java/io/rsocket/frame/{VersionFlyweight.java => VersionCodec.java} (96%) create mode 100644 rsocket-core/src/main/java/io/rsocket/metadata/AuthMetadataCodec.java create mode 100644 rsocket-core/src/main/java/io/rsocket/metadata/CompositeMetadataCodec.java create mode 100644 rsocket-core/src/main/java/io/rsocket/metadata/TaggingMetadataCodec.java create mode 100644 rsocket-core/src/main/java/io/rsocket/metadata/WellKnownAuthType.java rename rsocket-core/src/test/java/io/rsocket/frame/{ErrorFrameFlyweightTest.java => ErrorFrameCodecTest.java} (65%) create mode 100644 rsocket-core/src/test/java/io/rsocket/frame/ExtensionFrameCodecTest.java delete mode 100644 rsocket-core/src/test/java/io/rsocket/frame/ExtensionFrameFlyweightTest.java rename rsocket-core/src/test/java/io/rsocket/frame/{FrameHeaderFlyweightTest.java => FrameHeaderCodecTest.java} (52%) rename rsocket-core/src/test/java/io/rsocket/frame/{RequestFlyweightTest.java => GenericFrameCodecTest.java} (65%) create mode 100644 rsocket-core/src/test/java/io/rsocket/frame/LeaseFrameCodecTest.java delete mode 100644 rsocket-core/src/test/java/io/rsocket/frame/LeaseFrameFlyweightTest.java rename rsocket-core/src/test/java/io/rsocket/frame/{RequestNFrameFlyweightTest.java => RequestNFrameCodecTest.java} (63%) rename rsocket-core/src/test/java/io/rsocket/frame/{ResumeFrameFlyweightTest.java => ResumeFrameCodecTest.java} (68%) rename rsocket-core/src/test/java/io/rsocket/frame/{ResumeOkFrameFlyweightTest.java => ResumeOkFrameCodecTest.java} (51%) create mode 100644 rsocket-core/src/test/java/io/rsocket/frame/SetupFrameCodecTest.java delete mode 100644 rsocket-core/src/test/java/io/rsocket/frame/SetupFrameFlyweightTest.java rename rsocket-core/src/test/java/io/rsocket/frame/{VersionFlyweightTest.java => VersionCodecTest.java} (58%) diff --git a/rsocket-core/src/main/java/io/rsocket/core/DefaultConnectionSetupPayload.java b/rsocket-core/src/main/java/io/rsocket/core/DefaultConnectionSetupPayload.java index feeb5c481..9b5647c6f 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/DefaultConnectionSetupPayload.java +++ b/rsocket-core/src/main/java/io/rsocket/core/DefaultConnectionSetupPayload.java @@ -19,8 +19,8 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.rsocket.ConnectionSetupPayload; -import io.rsocket.frame.FrameHeaderFlyweight; -import io.rsocket.frame.SetupFrameFlyweight; +import io.rsocket.frame.FrameHeaderCodec; +import io.rsocket.frame.SetupFrameCodec; /** * Default implementation of {@link ConnectionSetupPayload}. Primarily for internal use within @@ -36,18 +36,18 @@ public DefaultConnectionSetupPayload(ByteBuf setupFrame) { @Override public boolean hasMetadata() { - return FrameHeaderFlyweight.hasMetadata(setupFrame); + return FrameHeaderCodec.hasMetadata(setupFrame); } @Override public ByteBuf sliceMetadata() { - final ByteBuf metadata = SetupFrameFlyweight.metadata(setupFrame); + final ByteBuf metadata = SetupFrameCodec.metadata(setupFrame); return metadata == null ? Unpooled.EMPTY_BUFFER : metadata; } @Override public ByteBuf sliceData() { - return SetupFrameFlyweight.data(setupFrame); + return SetupFrameCodec.data(setupFrame); } @Override @@ -62,42 +62,42 @@ public ByteBuf metadata() { @Override public String metadataMimeType() { - return SetupFrameFlyweight.metadataMimeType(setupFrame); + return SetupFrameCodec.metadataMimeType(setupFrame); } @Override public String dataMimeType() { - return SetupFrameFlyweight.dataMimeType(setupFrame); + return SetupFrameCodec.dataMimeType(setupFrame); } @Override public int keepAliveInterval() { - return SetupFrameFlyweight.keepAliveInterval(setupFrame); + return SetupFrameCodec.keepAliveInterval(setupFrame); } @Override public int keepAliveMaxLifetime() { - return SetupFrameFlyweight.keepAliveMaxLifetime(setupFrame); + return SetupFrameCodec.keepAliveMaxLifetime(setupFrame); } @Override public int getFlags() { - return FrameHeaderFlyweight.flags(setupFrame); + return FrameHeaderCodec.flags(setupFrame); } @Override public boolean willClientHonorLease() { - return SetupFrameFlyweight.honorLease(setupFrame); + return SetupFrameCodec.honorLease(setupFrame); } @Override public boolean isResumeEnabled() { - return SetupFrameFlyweight.resumeEnabled(setupFrame); + return SetupFrameCodec.resumeEnabled(setupFrame); } @Override public ByteBuf resumeToken() { - return SetupFrameFlyweight.resumeToken(setupFrame); + return SetupFrameCodec.resumeToken(setupFrame); } @Override diff --git a/rsocket-core/src/main/java/io/rsocket/core/PayloadValidationUtils.java b/rsocket-core/src/main/java/io/rsocket/core/PayloadValidationUtils.java index 3b6b375d1..2d2b96f7e 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/PayloadValidationUtils.java +++ b/rsocket-core/src/main/java/io/rsocket/core/PayloadValidationUtils.java @@ -1,8 +1,8 @@ package io.rsocket.core; import io.rsocket.Payload; -import io.rsocket.frame.FrameHeaderFlyweight; -import io.rsocket.frame.FrameLengthFlyweight; +import io.rsocket.frame.FrameHeaderCodec; +import io.rsocket.frame.FrameLengthCodec; final class PayloadValidationUtils { static final String INVALID_PAYLOAD_ERROR_MESSAGE = @@ -14,18 +14,18 @@ static boolean isValid(int mtu, Payload payload) { } if (payload.hasMetadata()) { - return (((FrameHeaderFlyweight.size() - + FrameLengthFlyweight.FRAME_LENGTH_SIZE - + FrameHeaderFlyweight.size() + return (((FrameHeaderCodec.size() + + FrameLengthCodec.FRAME_LENGTH_SIZE + + FrameHeaderCodec.size() + payload.data().readableBytes() + payload.metadata().readableBytes()) - & ~FrameLengthFlyweight.FRAME_LENGTH_MASK) + & ~FrameLengthCodec.FRAME_LENGTH_MASK) == 0); } else { - return (((FrameHeaderFlyweight.size() + return (((FrameHeaderCodec.size() + payload.data().readableBytes() - + FrameLengthFlyweight.FRAME_LENGTH_SIZE) - & ~FrameLengthFlyweight.FRAME_LENGTH_MASK) + + FrameLengthCodec.FRAME_LENGTH_SIZE) + & ~FrameLengthCodec.FRAME_LENGTH_MASK) == 0); } } diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java index 45d16a665..b69610f3f 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java @@ -23,7 +23,7 @@ import io.rsocket.RSocket; import io.rsocket.SocketAcceptor; import io.rsocket.fragmentation.FragmentationDuplexConnection; -import io.rsocket.frame.SetupFrameFlyweight; +import io.rsocket.frame.SetupFrameCodec; import io.rsocket.frame.decoder.PayloadDecoder; import io.rsocket.internal.ClientServerInputMultiplexer; import io.rsocket.keepalive.KeepAliveHandler; @@ -536,7 +536,7 @@ public Mono connect(Supplier transportSupplier) { RSocket wrappedRSocketRequester = interceptors.initRequester(rSocketRequester); ByteBuf setupFrame = - SetupFrameFlyweight.encode( + SetupFrameCodec.encode( wrappedConnection.alloc(), leaseEnabled, (int) keepAliveInterval.toMillis(), diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java index a2bd3d9fd..846eaa922 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java @@ -31,17 +31,17 @@ import io.rsocket.RSocket; import io.rsocket.exceptions.ConnectionErrorException; import io.rsocket.exceptions.Exceptions; -import io.rsocket.frame.CancelFrameFlyweight; -import io.rsocket.frame.ErrorFrameFlyweight; -import io.rsocket.frame.FrameHeaderFlyweight; +import io.rsocket.frame.CancelFrameCodec; +import io.rsocket.frame.ErrorFrameCodec; +import io.rsocket.frame.FrameHeaderCodec; import io.rsocket.frame.FrameType; -import io.rsocket.frame.MetadataPushFrameFlyweight; -import io.rsocket.frame.PayloadFrameFlyweight; -import io.rsocket.frame.RequestChannelFrameFlyweight; -import io.rsocket.frame.RequestFireAndForgetFrameFlyweight; -import io.rsocket.frame.RequestNFrameFlyweight; -import io.rsocket.frame.RequestResponseFrameFlyweight; -import io.rsocket.frame.RequestStreamFrameFlyweight; +import io.rsocket.frame.MetadataPushFrameCodec; +import io.rsocket.frame.PayloadFrameCodec; +import io.rsocket.frame.RequestChannelFrameCodec; +import io.rsocket.frame.RequestFireAndForgetFrameCodec; +import io.rsocket.frame.RequestNFrameCodec; +import io.rsocket.frame.RequestResponseFrameCodec; +import io.rsocket.frame.RequestStreamFrameCodec; import io.rsocket.frame.decoder.PayloadDecoder; import io.rsocket.internal.SynchronizedIntObjectHashMap; import io.rsocket.internal.UnboundedProcessor; @@ -225,7 +225,7 @@ private Mono handleFireAndForget(Payload payload) { final int streamId = streamIdSupplier.nextStreamId(receivers); final ByteBuf requestFrame = - RequestFireAndForgetFrameFlyweight.encodeReleasingPayload( + RequestFireAndForgetFrameCodec.encodeReleasingPayload( allocator, streamId, payload); sendProcessor.onNext(requestFrame); @@ -275,7 +275,7 @@ void hookOnFirstRequest(long n) { this.streamId = streamId; ByteBuf requestResponseFrame = - RequestResponseFrameFlyweight.encodeReleasingPayload( + RequestResponseFrameCodec.encodeReleasingPayload( allocator, streamId, payload); receivers.put(streamId, receiver); @@ -285,8 +285,7 @@ void hookOnFirstRequest(long n) { @Override void hookOnCancel() { if (receivers.remove(streamId, receiver)) { - sendProcessor.onNext( - CancelFrameFlyweight.encode(allocator, streamId)); + sendProcessor.onNext(CancelFrameCodec.encode(allocator, streamId)); } else { payload.release(); } @@ -341,7 +340,7 @@ void hookOnFirstRequest(long n) { this.streamId = streamId; ByteBuf requestStreamFrame = - RequestStreamFrameFlyweight.encodeReleasingPayload( + RequestStreamFrameCodec.encodeReleasingPayload( allocator, streamId, n, payload); receivers.put(streamId, receiver); @@ -356,14 +355,13 @@ void hookOnRemainingRequests(long n) { } sendProcessor.onNext( - RequestNFrameFlyweight.encode(allocator, streamId, n)); + RequestNFrameCodec.encode(allocator, streamId, n)); } @Override void hookOnCancel() { if (receivers.remove(streamId, receiver)) { - sendProcessor.onNext( - CancelFrameFlyweight.encode(allocator, streamId)); + sendProcessor.onNext(CancelFrameCodec.encode(allocator, streamId)); } else { payload.release(); } @@ -450,13 +448,12 @@ protected void hookOnNext(Payload payload) { new IllegalArgumentException(INVALID_PAYLOAD_ERROR_MESSAGE); errorConsumer.accept(t); // no need to send any errors. - sendProcessor.onNext( - CancelFrameFlyweight.encode(allocator, streamId)); + sendProcessor.onNext(CancelFrameCodec.encode(allocator, streamId)); receiver.onError(t); return; } final ByteBuf frame = - PayloadFrameFlyweight.encodeNextReleasingPayload( + PayloadFrameCodec.encodeNextReleasingPayload( allocator, streamId, payload); sendProcessor.onNext(frame); @@ -464,14 +461,13 @@ protected void hookOnNext(Payload payload) { @Override protected void hookOnComplete() { - ByteBuf frame = - PayloadFrameFlyweight.encodeComplete(allocator, streamId); + ByteBuf frame = PayloadFrameCodec.encodeComplete(allocator, streamId); sendProcessor.onNext(frame); } @Override protected void hookOnError(Throwable t) { - ByteBuf frame = ErrorFrameFlyweight.encode(allocator, streamId, t); + ByteBuf frame = ErrorFrameCodec.encode(allocator, streamId, t); sendProcessor.onNext(frame); receiver.onError(t); } @@ -488,7 +484,7 @@ void hookOnFirstRequest(long n) { this.streamId = streamId; final ByteBuf frame = - RequestChannelFrameFlyweight.encodeReleasingPayload( + RequestChannelFrameCodec.encodeReleasingPayload( allocator, streamId, false, n, initialPayload); senders.put(streamId, upstreamSubscriber); @@ -508,14 +504,14 @@ void hookOnRemainingRequests(long n) { return; } - sendProcessor.onNext(RequestNFrameFlyweight.encode(allocator, streamId, n)); + sendProcessor.onNext(RequestNFrameCodec.encode(allocator, streamId, n)); } @Override void hookOnCancel() { senders.remove(streamId, upstreamSubscriber); if (receivers.remove(streamId, receiver)) { - sendProcessor.onNext(CancelFrameFlyweight.encode(allocator, streamId)); + sendProcessor.onNext(CancelFrameCodec.encode(allocator, streamId)); } } @@ -562,7 +558,7 @@ private Mono handleMetadataPush(Payload payload) { } ByteBuf metadataPushFrame = - MetadataPushFrameFlyweight.encodeReleasingPayload(allocator, payload); + MetadataPushFrameCodec.encodeReleasingPayload(allocator, payload); sendProcessor.onNextPrioritized(metadataPushFrame); @@ -585,8 +581,8 @@ private Throwable checkAvailable() { private void handleIncomingFrames(ByteBuf frame) { try { - int streamId = FrameHeaderFlyweight.streamId(frame); - FrameType type = FrameHeaderFlyweight.frameType(frame); + int streamId = FrameHeaderCodec.streamId(frame); + FrameType type = FrameHeaderCodec.frameType(frame); if (streamId == 0) { handleStreamZero(type, frame); } else { @@ -666,7 +662,7 @@ private void handleFrame(int streamId, FrameType type, ByteBuf frame) { { Subscription sender = senders.get(streamId); if (sender != null) { - long n = RequestNFrameFlyweight.requestN(frame); + long n = RequestNFrameCodec.requestN(frame); sender.request(n); } break; @@ -682,7 +678,7 @@ private void handleMissingResponseProcessor(int streamId, FrameType type, ByteBu if (type == FrameType.ERROR) { // message for stream that has never existed, we have a problem with // the overall connection and must tear down - String errorMessage = ErrorFrameFlyweight.dataUtf8(frame); + String errorMessage = ErrorFrameCodec.dataUtf8(frame); throw new IllegalStateException( "Client received error for non-existent stream: " diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java index 2f073ba8a..b9d3ea794 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java @@ -292,9 +292,9 @@ private synchronized void cleanUpChannelProcessors(Throwable e) { private void handleFrame(ByteBuf frame) { try { - int streamId = FrameHeaderFlyweight.streamId(frame); + int streamId = FrameHeaderCodec.streamId(frame); Subscriber receiver; - FrameType frameType = FrameHeaderFlyweight.frameType(frame); + FrameType frameType = FrameHeaderCodec.frameType(frame); switch (frameType) { case REQUEST_FNF: handleFireAndForget(streamId, fireAndForget(payloadDecoder.apply(frame))); @@ -309,12 +309,12 @@ private void handleFrame(ByteBuf frame) { handleRequestN(streamId, frame); break; case REQUEST_STREAM: - long streamInitialRequestN = RequestStreamFrameFlyweight.initialRequestN(frame); + long streamInitialRequestN = RequestStreamFrameCodec.initialRequestN(frame); Payload streamPayload = payloadDecoder.apply(frame); handleStream(streamId, requestStream(streamPayload), streamInitialRequestN, null); break; case REQUEST_CHANNEL: - long channelInitialRequestN = RequestChannelFrameFlyweight.initialRequestN(frame); + long channelInitialRequestN = RequestChannelFrameCodec.initialRequestN(frame); Payload channelPayload = payloadDecoder.apply(frame); handleChannel(streamId, channelPayload, channelInitialRequestN); break; @@ -339,7 +339,7 @@ private void handleFrame(ByteBuf frame) { case ERROR: receiver = channelProcessors.get(streamId); if (receiver != null) { - receiver.onError(new ApplicationErrorException(ErrorFrameFlyweight.dataUtf8(frame))); + receiver.onError(new ApplicationErrorException(ErrorFrameCodec.dataUtf8(frame))); } break; case NEXT_COMPLETE: @@ -408,8 +408,7 @@ protected void hookOnNext(Payload payload) { } ByteBuf byteBuf = - PayloadFrameFlyweight.encodeNextCompleteReleasingPayload( - allocator, streamId, payload); + PayloadFrameCodec.encodeNextCompleteReleasingPayload(allocator, streamId, payload); sendProcessor.onNext(byteBuf); } @@ -421,7 +420,7 @@ protected void hookOnError(Throwable throwable) { @Override protected void hookOnComplete() { if (isEmpty) { - sendProcessor.onNext(PayloadFrameFlyweight.encodeComplete(allocator, streamId)); + sendProcessor.onNext(PayloadFrameCodec.encodeComplete(allocator, streamId)); } } @@ -473,7 +472,7 @@ protected void hookOnNext(Payload payload) { } ByteBuf byteBuf = - PayloadFrameFlyweight.encodeNextReleasingPayload(allocator, streamId, payload); + PayloadFrameCodec.encodeNextReleasingPayload(allocator, streamId, payload); sendProcessor.onNext(byteBuf); } catch (Throwable e) { // specifically for requestChannel case so when Payload is invalid we will not be @@ -494,7 +493,7 @@ protected void hookOnNext(Payload payload) { @Override protected void hookOnComplete() { - sendProcessor.onNext(PayloadFrameFlyweight.encodeComplete(allocator, streamId)); + sendProcessor.onNext(PayloadFrameCodec.encodeComplete(allocator, streamId)); } @Override @@ -553,7 +552,7 @@ public void accept(long l) { n = l; } if (n > 0) { - sendProcessor.onNext(RequestNFrameFlyweight.encode(allocator, streamId, n)); + sendProcessor.onNext(RequestNFrameCodec.encode(allocator, streamId, n)); } } }) @@ -561,7 +560,7 @@ public void accept(long l) { signalType -> { if (channelProcessors.remove(streamId, frames)) { if (signalType == SignalType.CANCEL) { - sendProcessor.onNext(CancelFrameFlyweight.encode(allocator, streamId)); + sendProcessor.onNext(CancelFrameCodec.encode(allocator, streamId)); } } }) @@ -605,14 +604,14 @@ private void handleCancelFrame(int streamId) { private void handleError(int streamId, Throwable t) { errorConsumer.accept(t); - sendProcessor.onNext(ErrorFrameFlyweight.encode(allocator, streamId, t)); + sendProcessor.onNext(ErrorFrameCodec.encode(allocator, streamId, t)); } private void handleRequestN(int streamId, ByteBuf frame) { Subscription subscription = sendingSubscriptions.get(streamId); if (subscription != null) { - long n = RequestNFrameFlyweight.requestN(frame); + long n = RequestNFrameCodec.requestN(frame); subscription.request(n); } } diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java index 5960e33d4..66e2249b5 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java @@ -26,8 +26,8 @@ import io.rsocket.exceptions.InvalidSetupException; import io.rsocket.exceptions.RejectedSetupException; import io.rsocket.fragmentation.FragmentationDuplexConnection; -import io.rsocket.frame.FrameHeaderFlyweight; -import io.rsocket.frame.SetupFrameFlyweight; +import io.rsocket.frame.FrameHeaderCodec; +import io.rsocket.frame.SetupFrameCodec; import io.rsocket.frame.decoder.PayloadDecoder; import io.rsocket.internal.ClientServerInputMultiplexer; import io.rsocket.lease.Leases; @@ -325,7 +325,7 @@ private Mono acceptResume( private Mono accept( ServerSetup serverSetup, ByteBuf startFrame, ClientServerInputMultiplexer multiplexer) { - switch (FrameHeaderFlyweight.frameType(startFrame)) { + switch (FrameHeaderCodec.frameType(startFrame)) { case SETUP: return acceptSetup(serverSetup, startFrame, multiplexer); case RESUME: @@ -335,7 +335,7 @@ private Mono accept( .sendError( multiplexer, new InvalidSetupException( - "invalid setup frame: " + FrameHeaderFlyweight.frameType(startFrame))) + "invalid setup frame: " + FrameHeaderCodec.frameType(startFrame))) .doFinally( signalType -> { startFrame.release(); @@ -347,12 +347,12 @@ private Mono accept( private Mono acceptSetup( ServerSetup serverSetup, ByteBuf setupFrame, ClientServerInputMultiplexer multiplexer) { - if (!SetupFrameFlyweight.isSupportedVersion(setupFrame)) { + if (!SetupFrameCodec.isSupportedVersion(setupFrame)) { return serverSetup .sendError( multiplexer, new InvalidSetupException( - "Unsupported version: " + SetupFrameFlyweight.humanReadableVersion(setupFrame))) + "Unsupported version: " + SetupFrameCodec.humanReadableVersion(setupFrame))) .doFinally( signalType -> { setupFrame.release(); @@ -361,7 +361,7 @@ private Mono acceptSetup( } boolean leaseEnabled = leasesSupplier != null; - if (SetupFrameFlyweight.honorLease(setupFrame) && !leaseEnabled) { + if (SetupFrameCodec.honorLease(setupFrame) && !leaseEnabled) { return serverSetup .sendError(multiplexer, new InvalidSetupException("lease is not supported")) .doFinally( diff --git a/rsocket-core/src/main/java/io/rsocket/core/Resume.java b/rsocket-core/src/main/java/io/rsocket/core/Resume.java index 04221154f..48133af98 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/Resume.java +++ b/rsocket-core/src/main/java/io/rsocket/core/Resume.java @@ -16,7 +16,7 @@ package io.rsocket.core; import io.netty.buffer.ByteBuf; -import io.rsocket.frame.ResumeFrameFlyweight; +import io.rsocket.frame.ResumeFrameCodec; import io.rsocket.resume.InMemoryResumableFramesStore; import io.rsocket.resume.ResumableFramesStore; import java.time.Duration; @@ -43,7 +43,7 @@ public class Resume { private Duration streamTimeout = Duration.ofSeconds(10); /* Client only */ - private Supplier tokenSupplier = ResumeFrameFlyweight::generateResumeToken; + private Supplier tokenSupplier = ResumeFrameCodec::generateResumeToken; private Retry retry = Retry.backoff(Long.MAX_VALUE, Duration.ofSeconds(1)) .maxBackoff(Duration.ofSeconds(16)) diff --git a/rsocket-core/src/main/java/io/rsocket/core/ServerSetup.java b/rsocket-core/src/main/java/io/rsocket/core/ServerSetup.java index 3e20d3c60..337d17c64 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/ServerSetup.java +++ b/rsocket-core/src/main/java/io/rsocket/core/ServerSetup.java @@ -22,9 +22,9 @@ import io.rsocket.DuplexConnection; import io.rsocket.exceptions.RejectedResumeException; import io.rsocket.exceptions.UnsupportedSetupException; -import io.rsocket.frame.ErrorFrameFlyweight; -import io.rsocket.frame.ResumeFrameFlyweight; -import io.rsocket.frame.SetupFrameFlyweight; +import io.rsocket.frame.ErrorFrameCodec; +import io.rsocket.frame.ResumeFrameCodec; +import io.rsocket.frame.SetupFrameCodec; import io.rsocket.internal.ClientServerInputMultiplexer; import io.rsocket.keepalive.KeepAliveHandler; import io.rsocket.resume.*; @@ -47,7 +47,7 @@ void dispose() {} Mono sendError(ClientServerInputMultiplexer multiplexer, Exception exception) { DuplexConnection duplexConnection = multiplexer.asSetupConnection(); return duplexConnection - .sendOne(ErrorFrameFlyweight.encode(duplexConnection.alloc(), 0, exception)) + .sendOne(ErrorFrameCodec.encode(duplexConnection.alloc(), 0, exception)) .onErrorResume(err -> Mono.empty()); } @@ -59,7 +59,7 @@ public Mono acceptRSocketSetup( ClientServerInputMultiplexer multiplexer, BiFunction> then) { - if (SetupFrameFlyweight.resumeEnabled(frame)) { + if (SetupFrameCodec.resumeEnabled(frame)) { return sendError(multiplexer, new UnsupportedSetupException("resume not supported")) .doFinally( signalType -> { @@ -109,8 +109,8 @@ public Mono acceptRSocketSetup( ClientServerInputMultiplexer multiplexer, BiFunction> then) { - if (SetupFrameFlyweight.resumeEnabled(frame)) { - ByteBuf resumeToken = SetupFrameFlyweight.resumeToken(frame); + if (SetupFrameCodec.resumeEnabled(frame)) { + ByteBuf resumeToken = SetupFrameCodec.resumeToken(frame); ResumableDuplexConnection connection = sessionManager @@ -133,7 +133,7 @@ public Mono acceptRSocketSetup( @Override public Mono acceptRSocketResume(ByteBuf frame, ClientServerInputMultiplexer multiplexer) { - ServerRSocketSession session = sessionManager.get(ResumeFrameFlyweight.token(frame)); + ServerRSocketSession session = sessionManager.get(ResumeFrameCodec.token(frame)); if (session != null) { return session .continueWith(multiplexer.asClientServerConnection()) diff --git a/rsocket-core/src/main/java/io/rsocket/exceptions/ApplicationErrorException.java b/rsocket-core/src/main/java/io/rsocket/exceptions/ApplicationErrorException.java index 351e045a3..e617b82d8 100644 --- a/rsocket-core/src/main/java/io/rsocket/exceptions/ApplicationErrorException.java +++ b/rsocket-core/src/main/java/io/rsocket/exceptions/ApplicationErrorException.java @@ -16,7 +16,7 @@ package io.rsocket.exceptions; -import io.rsocket.frame.ErrorFrameFlyweight; +import io.rsocket.frame.ErrorFrameCodec; import javax.annotation.Nullable; /** @@ -45,6 +45,6 @@ public ApplicationErrorException(String message) { * @param cause the cause of this exception */ public ApplicationErrorException(String message, @Nullable Throwable cause) { - super(ErrorFrameFlyweight.APPLICATION_ERROR, message, cause); + super(ErrorFrameCodec.APPLICATION_ERROR, message, cause); } } diff --git a/rsocket-core/src/main/java/io/rsocket/exceptions/CanceledException.java b/rsocket-core/src/main/java/io/rsocket/exceptions/CanceledException.java index 537cf2bf2..3c5fc7420 100644 --- a/rsocket-core/src/main/java/io/rsocket/exceptions/CanceledException.java +++ b/rsocket-core/src/main/java/io/rsocket/exceptions/CanceledException.java @@ -16,7 +16,7 @@ package io.rsocket.exceptions; -import io.rsocket.frame.ErrorFrameFlyweight; +import io.rsocket.frame.ErrorFrameCodec; import javax.annotation.Nullable; /** @@ -46,6 +46,6 @@ public CanceledException(String message) { * @param cause the cause of this exception */ public CanceledException(String message, @Nullable Throwable cause) { - super(ErrorFrameFlyweight.CANCELED, message, cause); + super(ErrorFrameCodec.CANCELED, message, cause); } } diff --git a/rsocket-core/src/main/java/io/rsocket/exceptions/ConnectionCloseException.java b/rsocket-core/src/main/java/io/rsocket/exceptions/ConnectionCloseException.java index f1f1a47d8..5cff2c821 100644 --- a/rsocket-core/src/main/java/io/rsocket/exceptions/ConnectionCloseException.java +++ b/rsocket-core/src/main/java/io/rsocket/exceptions/ConnectionCloseException.java @@ -16,7 +16,7 @@ package io.rsocket.exceptions; -import io.rsocket.frame.ErrorFrameFlyweight; +import io.rsocket.frame.ErrorFrameCodec; import javax.annotation.Nullable; /** @@ -46,6 +46,6 @@ public ConnectionCloseException(String message) { * @param cause the cause of this exception */ public ConnectionCloseException(String message, @Nullable Throwable cause) { - super(ErrorFrameFlyweight.CONNECTION_CLOSE, message, cause); + super(ErrorFrameCodec.CONNECTION_CLOSE, message, cause); } } diff --git a/rsocket-core/src/main/java/io/rsocket/exceptions/ConnectionErrorException.java b/rsocket-core/src/main/java/io/rsocket/exceptions/ConnectionErrorException.java index 9581cfc97..3fcb8f5de 100644 --- a/rsocket-core/src/main/java/io/rsocket/exceptions/ConnectionErrorException.java +++ b/rsocket-core/src/main/java/io/rsocket/exceptions/ConnectionErrorException.java @@ -16,7 +16,7 @@ package io.rsocket.exceptions; -import io.rsocket.frame.ErrorFrameFlyweight; +import io.rsocket.frame.ErrorFrameCodec; import javax.annotation.Nullable; /** @@ -46,6 +46,6 @@ public ConnectionErrorException(String message) { * @param cause the cause of this exception */ public ConnectionErrorException(String message, @Nullable Throwable cause) { - super(ErrorFrameFlyweight.CONNECTION_ERROR, message, cause); + super(ErrorFrameCodec.CONNECTION_ERROR, message, cause); } } diff --git a/rsocket-core/src/main/java/io/rsocket/exceptions/CustomRSocketException.java b/rsocket-core/src/main/java/io/rsocket/exceptions/CustomRSocketException.java index 5c1154ebd..18f488ba0 100644 --- a/rsocket-core/src/main/java/io/rsocket/exceptions/CustomRSocketException.java +++ b/rsocket-core/src/main/java/io/rsocket/exceptions/CustomRSocketException.java @@ -16,7 +16,7 @@ package io.rsocket.exceptions; -import io.rsocket.frame.ErrorFrameFlyweight; +import io.rsocket.frame.ErrorFrameCodec; import javax.annotation.Nullable; public class CustomRSocketException extends RSocketException { @@ -43,8 +43,8 @@ public CustomRSocketException(int errorCode, String message) { */ public CustomRSocketException(int errorCode, String message, @Nullable Throwable cause) { super(errorCode, message, cause); - if (errorCode > ErrorFrameFlyweight.MAX_USER_ALLOWED_ERROR_CODE - && errorCode < ErrorFrameFlyweight.MIN_USER_ALLOWED_ERROR_CODE) { + if (errorCode > ErrorFrameCodec.MAX_USER_ALLOWED_ERROR_CODE + && errorCode < ErrorFrameCodec.MIN_USER_ALLOWED_ERROR_CODE) { throw new IllegalArgumentException( "Allowed errorCode value should be in range [0x00000301-0xFFFFFFFE]", this); } diff --git a/rsocket-core/src/main/java/io/rsocket/exceptions/Exceptions.java b/rsocket-core/src/main/java/io/rsocket/exceptions/Exceptions.java index fe2d304f5..5c6eee614 100644 --- a/rsocket-core/src/main/java/io/rsocket/exceptions/Exceptions.java +++ b/rsocket-core/src/main/java/io/rsocket/exceptions/Exceptions.java @@ -16,22 +16,22 @@ package io.rsocket.exceptions; -import static io.rsocket.frame.ErrorFrameFlyweight.APPLICATION_ERROR; -import static io.rsocket.frame.ErrorFrameFlyweight.CANCELED; -import static io.rsocket.frame.ErrorFrameFlyweight.CONNECTION_CLOSE; -import static io.rsocket.frame.ErrorFrameFlyweight.CONNECTION_ERROR; -import static io.rsocket.frame.ErrorFrameFlyweight.INVALID; -import static io.rsocket.frame.ErrorFrameFlyweight.INVALID_SETUP; -import static io.rsocket.frame.ErrorFrameFlyweight.MAX_USER_ALLOWED_ERROR_CODE; -import static io.rsocket.frame.ErrorFrameFlyweight.MIN_USER_ALLOWED_ERROR_CODE; -import static io.rsocket.frame.ErrorFrameFlyweight.REJECTED; -import static io.rsocket.frame.ErrorFrameFlyweight.REJECTED_RESUME; -import static io.rsocket.frame.ErrorFrameFlyweight.REJECTED_SETUP; -import static io.rsocket.frame.ErrorFrameFlyweight.UNSUPPORTED_SETUP; +import static io.rsocket.frame.ErrorFrameCodec.APPLICATION_ERROR; +import static io.rsocket.frame.ErrorFrameCodec.CANCELED; +import static io.rsocket.frame.ErrorFrameCodec.CONNECTION_CLOSE; +import static io.rsocket.frame.ErrorFrameCodec.CONNECTION_ERROR; +import static io.rsocket.frame.ErrorFrameCodec.INVALID; +import static io.rsocket.frame.ErrorFrameCodec.INVALID_SETUP; +import static io.rsocket.frame.ErrorFrameCodec.MAX_USER_ALLOWED_ERROR_CODE; +import static io.rsocket.frame.ErrorFrameCodec.MIN_USER_ALLOWED_ERROR_CODE; +import static io.rsocket.frame.ErrorFrameCodec.REJECTED; +import static io.rsocket.frame.ErrorFrameCodec.REJECTED_RESUME; +import static io.rsocket.frame.ErrorFrameCodec.REJECTED_SETUP; +import static io.rsocket.frame.ErrorFrameCodec.UNSUPPORTED_SETUP; import io.netty.buffer.ByteBuf; import io.rsocket.RSocketErrorException; -import io.rsocket.frame.ErrorFrameFlyweight; +import io.rsocket.frame.ErrorFrameCodec; import java.util.Objects; /** Utility class that generates an exception from a frame. */ @@ -49,8 +49,8 @@ private Exceptions() {} public static RuntimeException from(int streamId, ByteBuf frame) { Objects.requireNonNull(frame, "frame must not be null"); - int errorCode = ErrorFrameFlyweight.errorCode(frame); - String message = ErrorFrameFlyweight.dataUtf8(frame); + int errorCode = ErrorFrameCodec.errorCode(frame); + String message = ErrorFrameCodec.dataUtf8(frame); if (streamId == 0) { switch (errorCode) { diff --git a/rsocket-core/src/main/java/io/rsocket/exceptions/InvalidException.java b/rsocket-core/src/main/java/io/rsocket/exceptions/InvalidException.java index a4b28659f..2428d1e7e 100644 --- a/rsocket-core/src/main/java/io/rsocket/exceptions/InvalidException.java +++ b/rsocket-core/src/main/java/io/rsocket/exceptions/InvalidException.java @@ -16,7 +16,7 @@ package io.rsocket.exceptions; -import io.rsocket.frame.ErrorFrameFlyweight; +import io.rsocket.frame.ErrorFrameCodec; import javax.annotation.Nullable; /** @@ -45,6 +45,6 @@ public InvalidException(String message) { * @param cause the cause of this exception */ public InvalidException(String message, @Nullable Throwable cause) { - super(ErrorFrameFlyweight.INVALID, message, cause); + super(ErrorFrameCodec.INVALID, message, cause); } } diff --git a/rsocket-core/src/main/java/io/rsocket/exceptions/InvalidSetupException.java b/rsocket-core/src/main/java/io/rsocket/exceptions/InvalidSetupException.java index 1ff53d51d..57da19bb6 100644 --- a/rsocket-core/src/main/java/io/rsocket/exceptions/InvalidSetupException.java +++ b/rsocket-core/src/main/java/io/rsocket/exceptions/InvalidSetupException.java @@ -16,7 +16,7 @@ package io.rsocket.exceptions; -import io.rsocket.frame.ErrorFrameFlyweight; +import io.rsocket.frame.ErrorFrameCodec; import javax.annotation.Nullable; /** @@ -46,6 +46,6 @@ public InvalidSetupException(String message) { * @param cause the cause of this exception */ public InvalidSetupException(String message, @Nullable Throwable cause) { - super(ErrorFrameFlyweight.INVALID_SETUP, message, cause); + super(ErrorFrameCodec.INVALID_SETUP, message, cause); } } diff --git a/rsocket-core/src/main/java/io/rsocket/exceptions/RSocketException.java b/rsocket-core/src/main/java/io/rsocket/exceptions/RSocketException.java index 93c49d5e2..2b137282f 100644 --- a/rsocket-core/src/main/java/io/rsocket/exceptions/RSocketException.java +++ b/rsocket-core/src/main/java/io/rsocket/exceptions/RSocketException.java @@ -17,7 +17,7 @@ package io.rsocket.exceptions; import io.rsocket.RSocketErrorException; -import io.rsocket.frame.ErrorFrameFlyweight; +import io.rsocket.frame.ErrorFrameCodec; import reactor.util.annotation.Nullable; /** @@ -47,7 +47,7 @@ public RSocketException(String message) { * @param cause the cause of this exception */ public RSocketException(String message, @Nullable Throwable cause) { - super(ErrorFrameFlyweight.APPLICATION_ERROR, message, cause); + super(ErrorFrameCodec.APPLICATION_ERROR, message, cause); } /** diff --git a/rsocket-core/src/main/java/io/rsocket/exceptions/RejectedException.java b/rsocket-core/src/main/java/io/rsocket/exceptions/RejectedException.java index 3fad3f396..c87a60243 100644 --- a/rsocket-core/src/main/java/io/rsocket/exceptions/RejectedException.java +++ b/rsocket-core/src/main/java/io/rsocket/exceptions/RejectedException.java @@ -16,7 +16,7 @@ package io.rsocket.exceptions; -import io.rsocket.frame.ErrorFrameFlyweight; +import io.rsocket.frame.ErrorFrameCodec; import javax.annotation.Nullable; /** @@ -47,6 +47,6 @@ public RejectedException(String message) { * @param cause the cause of this exception */ public RejectedException(String message, @Nullable Throwable cause) { - super(ErrorFrameFlyweight.REJECTED, message, cause); + super(ErrorFrameCodec.REJECTED, message, cause); } } diff --git a/rsocket-core/src/main/java/io/rsocket/exceptions/RejectedResumeException.java b/rsocket-core/src/main/java/io/rsocket/exceptions/RejectedResumeException.java index a10eb4197..8a6ea2244 100644 --- a/rsocket-core/src/main/java/io/rsocket/exceptions/RejectedResumeException.java +++ b/rsocket-core/src/main/java/io/rsocket/exceptions/RejectedResumeException.java @@ -16,7 +16,7 @@ package io.rsocket.exceptions; -import io.rsocket.frame.ErrorFrameFlyweight; +import io.rsocket.frame.ErrorFrameCodec; import javax.annotation.Nullable; /** @@ -45,6 +45,6 @@ public RejectedResumeException(String message) { * @param cause the cause of this exception */ public RejectedResumeException(String message, @Nullable Throwable cause) { - super(ErrorFrameFlyweight.REJECTED_RESUME, message, cause); + super(ErrorFrameCodec.REJECTED_RESUME, message, cause); } } diff --git a/rsocket-core/src/main/java/io/rsocket/exceptions/RejectedSetupException.java b/rsocket-core/src/main/java/io/rsocket/exceptions/RejectedSetupException.java index 6b5dc0f8b..972b430a7 100644 --- a/rsocket-core/src/main/java/io/rsocket/exceptions/RejectedSetupException.java +++ b/rsocket-core/src/main/java/io/rsocket/exceptions/RejectedSetupException.java @@ -16,7 +16,7 @@ package io.rsocket.exceptions; -import io.rsocket.frame.ErrorFrameFlyweight; +import io.rsocket.frame.ErrorFrameCodec; import javax.annotation.Nullable; /** @@ -45,6 +45,6 @@ public RejectedSetupException(String message) { * @param cause the cause of this exception */ public RejectedSetupException(String message, @Nullable Throwable cause) { - super(ErrorFrameFlyweight.REJECTED_SETUP, message, cause); + super(ErrorFrameCodec.REJECTED_SETUP, message, cause); } } diff --git a/rsocket-core/src/main/java/io/rsocket/exceptions/SetupException.java b/rsocket-core/src/main/java/io/rsocket/exceptions/SetupException.java index 712508f0b..158e5410d 100644 --- a/rsocket-core/src/main/java/io/rsocket/exceptions/SetupException.java +++ b/rsocket-core/src/main/java/io/rsocket/exceptions/SetupException.java @@ -16,7 +16,7 @@ package io.rsocket.exceptions; -import io.rsocket.frame.ErrorFrameFlyweight; +import io.rsocket.frame.ErrorFrameCodec; import javax.annotation.Nullable; /** The root of the setup exception hierarchy. */ @@ -44,7 +44,7 @@ public SetupException(String message) { */ @Deprecated public SetupException(String message, @Nullable Throwable cause) { - this(ErrorFrameFlyweight.INVALID_SETUP, message, cause); + this(ErrorFrameCodec.INVALID_SETUP, message, cause); } /** diff --git a/rsocket-core/src/main/java/io/rsocket/exceptions/UnsupportedSetupException.java b/rsocket-core/src/main/java/io/rsocket/exceptions/UnsupportedSetupException.java index b112b95be..3282c9750 100644 --- a/rsocket-core/src/main/java/io/rsocket/exceptions/UnsupportedSetupException.java +++ b/rsocket-core/src/main/java/io/rsocket/exceptions/UnsupportedSetupException.java @@ -16,7 +16,7 @@ package io.rsocket.exceptions; -import io.rsocket.frame.ErrorFrameFlyweight; +import io.rsocket.frame.ErrorFrameCodec; import javax.annotation.Nullable; /** @@ -45,6 +45,6 @@ public UnsupportedSetupException(String message) { * @param cause the cause of this exception */ public UnsupportedSetupException(String message, @Nullable Throwable cause) { - super(ErrorFrameFlyweight.UNSUPPORTED_SETUP, message, cause); + super(ErrorFrameCodec.UNSUPPORTED_SETUP, message, cause); } } diff --git a/rsocket-core/src/main/java/io/rsocket/fragmentation/FragmentationDuplexConnection.java b/rsocket-core/src/main/java/io/rsocket/fragmentation/FragmentationDuplexConnection.java index 24b360755..5192ffead 100644 --- a/rsocket-core/src/main/java/io/rsocket/fragmentation/FragmentationDuplexConnection.java +++ b/rsocket-core/src/main/java/io/rsocket/fragmentation/FragmentationDuplexConnection.java @@ -21,8 +21,8 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.rsocket.DuplexConnection; -import io.rsocket.frame.FrameHeaderFlyweight; -import io.rsocket.frame.FrameLengthFlyweight; +import io.rsocket.frame.FrameHeaderCodec; +import io.rsocket.frame.FrameLengthCodec; import io.rsocket.frame.FrameType; import java.util.Objects; import javax.annotation.Nullable; @@ -100,7 +100,7 @@ public Mono send(Publisher frames) { @Override public Mono sendOne(ByteBuf frame) { - FrameType frameType = FrameHeaderFlyweight.frameType(frame); + FrameType frameType = FrameHeaderCodec.frameType(frame); int readableBytes = frame.readableBytes(); if (shouldFragment(frameType, readableBytes)) { if (logger.isDebugEnabled()) { @@ -108,12 +108,12 @@ public Mono sendOne(ByteBuf frame) { Flux.from(fragmentFrame(alloc(), mtu, frame, frameType, encodeLength)) .doOnNext( byteBuf -> { - ByteBuf f = encodeLength ? FrameLengthFlyweight.frame(byteBuf) : byteBuf; + ByteBuf f = encodeLength ? FrameLengthCodec.frame(byteBuf) : byteBuf; logger.debug( "{} - stream id {} - frame type {} - \n {}", type, - FrameHeaderFlyweight.streamId(f), - FrameHeaderFlyweight.frameType(f), + FrameHeaderCodec.streamId(f), + FrameHeaderCodec.frameType(f), ByteBufUtil.prettyHexDump(f)); })); } else { @@ -127,7 +127,7 @@ public Mono sendOne(ByteBuf frame) { private ByteBuf encode(ByteBuf frame) { if (encodeLength) { - return FrameLengthFlyweight.encode(alloc(), frame.readableBytes(), frame); + return FrameLengthCodec.encode(alloc(), frame.readableBytes(), frame); } else { return frame; } diff --git a/rsocket-core/src/main/java/io/rsocket/fragmentation/FrameFragmenter.java b/rsocket-core/src/main/java/io/rsocket/fragmentation/FrameFragmenter.java index 8593d2be7..4b8fd36e9 100644 --- a/rsocket-core/src/main/java/io/rsocket/fragmentation/FrameFragmenter.java +++ b/rsocket-core/src/main/java/io/rsocket/fragmentation/FrameFragmenter.java @@ -20,14 +20,14 @@ import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.Unpooled; import io.netty.util.ReferenceCountUtil; -import io.rsocket.frame.FrameHeaderFlyweight; -import io.rsocket.frame.FrameLengthFlyweight; +import io.rsocket.frame.FrameHeaderCodec; +import io.rsocket.frame.FrameLengthCodec; import io.rsocket.frame.FrameType; -import io.rsocket.frame.PayloadFrameFlyweight; -import io.rsocket.frame.RequestChannelFrameFlyweight; -import io.rsocket.frame.RequestFireAndForgetFrameFlyweight; -import io.rsocket.frame.RequestResponseFrameFlyweight; -import io.rsocket.frame.RequestStreamFrameFlyweight; +import io.rsocket.frame.PayloadFrameCodec; +import io.rsocket.frame.RequestChannelFrameCodec; +import io.rsocket.frame.RequestFireAndForgetFrameCodec; +import io.rsocket.frame.RequestResponseFrameCodec; +import io.rsocket.frame.RequestStreamFrameCodec; import java.util.function.Consumer; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; @@ -49,7 +49,7 @@ static Publisher fragmentFrame( boolean encodeLength) { ByteBuf metadata = getMetadata(frame, frameType); ByteBuf data = getData(frame, frameType); - int streamId = FrameHeaderFlyweight.streamId(frame); + int streamId = FrameHeaderCodec.streamId(frame); return Flux.generate( new Consumer>() { boolean first = true; @@ -84,7 +84,7 @@ static ByteBuf encodeFirstFragment( ByteBuf metadata, ByteBuf data) { // subtract the header bytes - int remaining = mtu - FrameHeaderFlyweight.size(); + int remaining = mtu - FrameHeaderCodec.size(); // substract the initial request n switch (frameType) { @@ -112,40 +112,40 @@ static ByteBuf encodeFirstFragment( switch (frameType) { case REQUEST_FNF: - return RequestFireAndForgetFrameFlyweight.encode( + return RequestFireAndForgetFrameCodec.encode( allocator, streamId, true, metadataFragment, dataFragment); case REQUEST_STREAM: - return RequestStreamFrameFlyweight.encode( + return RequestStreamFrameCodec.encode( allocator, streamId, true, - RequestStreamFrameFlyweight.initialRequestN(frame), + RequestStreamFrameCodec.initialRequestN(frame), metadataFragment, dataFragment); case REQUEST_RESPONSE: - return RequestResponseFrameFlyweight.encode( + return RequestResponseFrameCodec.encode( allocator, streamId, true, metadataFragment, dataFragment); case REQUEST_CHANNEL: - return RequestChannelFrameFlyweight.encode( + return RequestChannelFrameCodec.encode( allocator, streamId, true, false, - RequestChannelFrameFlyweight.initialRequestN(frame), + RequestChannelFrameCodec.initialRequestN(frame), metadataFragment, dataFragment); // Payload and synthetic types case PAYLOAD: - return PayloadFrameFlyweight.encode( + return PayloadFrameCodec.encode( allocator, streamId, true, false, false, metadataFragment, dataFragment); case NEXT: - return PayloadFrameFlyweight.encode( + return PayloadFrameCodec.encode( allocator, streamId, true, false, true, metadataFragment, dataFragment); case NEXT_COMPLETE: - return PayloadFrameFlyweight.encode( + return PayloadFrameCodec.encode( allocator, streamId, true, true, true, metadataFragment, dataFragment); case COMPLETE: - return PayloadFrameFlyweight.encode( + return PayloadFrameCodec.encode( allocator, streamId, true, true, false, metadataFragment, dataFragment); default: throw new IllegalStateException("unsupported fragment type: " + frameType); @@ -155,7 +155,7 @@ static ByteBuf encodeFirstFragment( static ByteBuf encodeFollowsFragment( ByteBufAllocator allocator, int mtu, int streamId, ByteBuf metadata, ByteBuf data) { // subtract the header bytes - int remaining = mtu - FrameHeaderFlyweight.size(); + int remaining = mtu - FrameHeaderCodec.size(); ByteBuf metadataFragment = null; if (metadata.isReadable()) { @@ -173,33 +173,33 @@ static ByteBuf encodeFollowsFragment( } boolean follows = data.isReadable() || metadata.isReadable(); - return PayloadFrameFlyweight.encode( + return PayloadFrameCodec.encode( allocator, streamId, follows, false, true, metadataFragment, dataFragment); } static ByteBuf getMetadata(ByteBuf frame, FrameType frameType) { - boolean hasMetadata = FrameHeaderFlyweight.hasMetadata(frame); + boolean hasMetadata = FrameHeaderCodec.hasMetadata(frame); if (hasMetadata) { ByteBuf metadata; switch (frameType) { case REQUEST_FNF: - metadata = RequestFireAndForgetFrameFlyweight.metadata(frame); + metadata = RequestFireAndForgetFrameCodec.metadata(frame); break; case REQUEST_STREAM: - metadata = RequestStreamFrameFlyweight.metadata(frame); + metadata = RequestStreamFrameCodec.metadata(frame); break; case REQUEST_RESPONSE: - metadata = RequestResponseFrameFlyweight.metadata(frame); + metadata = RequestResponseFrameCodec.metadata(frame); break; case REQUEST_CHANNEL: - metadata = RequestChannelFrameFlyweight.metadata(frame); + metadata = RequestChannelFrameCodec.metadata(frame); break; // Payload and synthetic types case PAYLOAD: case NEXT: case NEXT_COMPLETE: case COMPLETE: - metadata = PayloadFrameFlyweight.metadata(frame); + metadata = PayloadFrameCodec.metadata(frame); break; default: throw new IllegalStateException("unsupported fragment type"); @@ -214,23 +214,23 @@ static ByteBuf getData(ByteBuf frame, FrameType frameType) { ByteBuf data; switch (frameType) { case REQUEST_FNF: - data = RequestFireAndForgetFrameFlyweight.data(frame); + data = RequestFireAndForgetFrameCodec.data(frame); break; case REQUEST_STREAM: - data = RequestStreamFrameFlyweight.data(frame); + data = RequestStreamFrameCodec.data(frame); break; case REQUEST_RESPONSE: - data = RequestResponseFrameFlyweight.data(frame); + data = RequestResponseFrameCodec.data(frame); break; case REQUEST_CHANNEL: - data = RequestChannelFrameFlyweight.data(frame); + data = RequestChannelFrameCodec.data(frame); break; // Payload and synthetic types case PAYLOAD: case NEXT: case NEXT_COMPLETE: case COMPLETE: - data = PayloadFrameFlyweight.data(frame); + data = PayloadFrameCodec.data(frame); break; default: throw new IllegalStateException("unsupported fragment type"); @@ -240,7 +240,7 @@ static ByteBuf getData(ByteBuf frame, FrameType frameType) { static ByteBuf encode(ByteBufAllocator allocator, ByteBuf frame, boolean encodeLength) { if (encodeLength) { - return FrameLengthFlyweight.encode(allocator, frame.readableBytes(), frame); + return FrameLengthCodec.encode(allocator, frame.readableBytes(), frame); } else { return frame; } diff --git a/rsocket-core/src/main/java/io/rsocket/fragmentation/FrameReassembler.java b/rsocket-core/src/main/java/io/rsocket/fragmentation/FrameReassembler.java index 1a8d242b2..1e96bd1fc 100644 --- a/rsocket-core/src/main/java/io/rsocket/fragmentation/FrameReassembler.java +++ b/rsocket-core/src/main/java/io/rsocket/fragmentation/FrameReassembler.java @@ -146,12 +146,12 @@ void cancelAssemble(int streamId) { void handleNoFollowsFlag(ByteBuf frame, SynchronousSink sink, int streamId) { ByteBuf header = removeHeader(streamId); if (header != null) { - if (FrameHeaderFlyweight.hasMetadata(header)) { + if (FrameHeaderCodec.hasMetadata(header)) { ByteBuf assembledFrame = assembleFrameWithMetadata(frame, streamId, header); sink.next(assembledFrame); } else { ByteBuf data = assembleData(frame, streamId); - ByteBuf assembledFrame = FragmentationFlyweight.encode(allocator, header, data); + ByteBuf assembledFrame = FragmentationCodec.encode(allocator, header, data); sink.next(assembledFrame); } frame.release(); @@ -163,36 +163,36 @@ void handleNoFollowsFlag(ByteBuf frame, SynchronousSink sink, int strea void handleFollowsFlag(ByteBuf frame, int streamId, FrameType frameType) { ByteBuf header = getHeader(streamId); if (header == null) { - header = frame.copy(frame.readerIndex(), FrameHeaderFlyweight.size()); + header = frame.copy(frame.readerIndex(), FrameHeaderCodec.size()); if (frameType == FrameType.REQUEST_CHANNEL || frameType == FrameType.REQUEST_STREAM) { - long i = RequestChannelFrameFlyweight.initialRequestN(frame); + long i = RequestChannelFrameCodec.initialRequestN(frame); header.writeInt(i > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) i); } putHeader(streamId, header); } - if (FrameHeaderFlyweight.hasMetadata(frame)) { + if (FrameHeaderCodec.hasMetadata(frame)) { CompositeByteBuf metadata = getMetadata(streamId); switch (frameType) { case REQUEST_FNF: - metadata.addComponents(true, RequestFireAndForgetFrameFlyweight.metadata(frame).retain()); + metadata.addComponents(true, RequestFireAndForgetFrameCodec.metadata(frame).retain()); break; case REQUEST_STREAM: - metadata.addComponents(true, RequestStreamFrameFlyweight.metadata(frame).retain()); + metadata.addComponents(true, RequestStreamFrameCodec.metadata(frame).retain()); break; case REQUEST_RESPONSE: - metadata.addComponents(true, RequestResponseFrameFlyweight.metadata(frame).retain()); + metadata.addComponents(true, RequestResponseFrameCodec.metadata(frame).retain()); break; case REQUEST_CHANNEL: - metadata.addComponents(true, RequestChannelFrameFlyweight.metadata(frame).retain()); + metadata.addComponents(true, RequestChannelFrameCodec.metadata(frame).retain()); break; // Payload and synthetic types case PAYLOAD: case NEXT: case NEXT_COMPLETE: case COMPLETE: - metadata.addComponents(true, PayloadFrameFlyweight.metadata(frame).retain()); + metadata.addComponents(true, PayloadFrameCodec.metadata(frame).retain()); break; default: throw new IllegalStateException("unsupported fragment type"); @@ -202,23 +202,23 @@ void handleFollowsFlag(ByteBuf frame, int streamId, FrameType frameType) { ByteBuf data; switch (frameType) { case REQUEST_FNF: - data = RequestFireAndForgetFrameFlyweight.data(frame).retain(); + data = RequestFireAndForgetFrameCodec.data(frame).retain(); break; case REQUEST_STREAM: - data = RequestStreamFrameFlyweight.data(frame).retain(); + data = RequestStreamFrameCodec.data(frame).retain(); break; case REQUEST_RESPONSE: - data = RequestResponseFrameFlyweight.data(frame).retain(); + data = RequestResponseFrameCodec.data(frame).retain(); break; case REQUEST_CHANNEL: - data = RequestChannelFrameFlyweight.data(frame).retain(); + data = RequestChannelFrameCodec.data(frame).retain(); break; // Payload and synthetic types case PAYLOAD: case NEXT: case NEXT_COMPLETE: case COMPLETE: - data = PayloadFrameFlyweight.data(frame).retain(); + data = PayloadFrameCodec.data(frame).retain(); break; default: throw new IllegalStateException("unsupported fragment type"); @@ -230,8 +230,8 @@ void handleFollowsFlag(ByteBuf frame, int streamId, FrameType frameType) { void reassembleFrame(ByteBuf frame, SynchronousSink sink) { try { - FrameType frameType = FrameHeaderFlyweight.frameType(frame); - int streamId = FrameHeaderFlyweight.streamId(frame); + FrameType frameType = FrameHeaderCodec.frameType(frame); + int streamId = FrameHeaderCodec.streamId(frame); switch (frameType) { case CANCEL: case ERROR: @@ -244,7 +244,7 @@ void reassembleFrame(ByteBuf frame, SynchronousSink sink) { return; } - boolean hasFollows = FrameHeaderFlyweight.hasFollows(frame); + boolean hasFollows = FrameHeaderCodec.hasFollows(frame); if (hasFollows) { handleFollowsFlag(frame, streamId, frameType); @@ -262,12 +262,12 @@ private ByteBuf assembleFrameWithMetadata(ByteBuf frame, int streamId, ByteBuf h ByteBuf metadata; CompositeByteBuf cm = removeMetadata(streamId); - ByteBuf decodedMetadata = PayloadFrameFlyweight.metadata(frame); + ByteBuf decodedMetadata = PayloadFrameCodec.metadata(frame); if (decodedMetadata != null) { if (cm != null) { metadata = cm.addComponents(true, decodedMetadata.retain()); } else { - metadata = PayloadFrameFlyweight.metadata(frame).retain(); + metadata = PayloadFrameCodec.metadata(frame).retain(); } } else { metadata = cm != null ? cm : null; @@ -275,14 +275,14 @@ private ByteBuf assembleFrameWithMetadata(ByteBuf frame, int streamId, ByteBuf h ByteBuf data = assembleData(frame, streamId); - return FragmentationFlyweight.encode(allocator, header, metadata, data); + return FragmentationCodec.encode(allocator, header, metadata, data); } private ByteBuf assembleData(ByteBuf frame, int streamId) { ByteBuf data; CompositeByteBuf cd = removeData(streamId); if (cd != null) { - cd.addComponents(true, PayloadFrameFlyweight.data(frame).retain()); + cd.addComponents(true, PayloadFrameCodec.data(frame).retain()); data = cd; } else { data = Unpooled.EMPTY_BUFFER; diff --git a/rsocket-core/src/main/java/io/rsocket/fragmentation/ReassemblyDuplexConnection.java b/rsocket-core/src/main/java/io/rsocket/fragmentation/ReassemblyDuplexConnection.java index 933755bb2..6060c0c20 100644 --- a/rsocket-core/src/main/java/io/rsocket/fragmentation/ReassemblyDuplexConnection.java +++ b/rsocket-core/src/main/java/io/rsocket/fragmentation/ReassemblyDuplexConnection.java @@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.rsocket.DuplexConnection; -import io.rsocket.frame.FrameLengthFlyweight; +import io.rsocket.frame.FrameLengthCodec; import java.util.Objects; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; @@ -58,7 +58,7 @@ public Mono sendOne(ByteBuf frame) { private ByteBuf decode(ByteBuf frame) { if (decodeLength) { - return FrameLengthFlyweight.frame(frame).retain(); + return FrameLengthCodec.frame(frame).retain(); } else { return frame; } diff --git a/rsocket-core/src/main/java/io/rsocket/frame/CancelFrameFlyweight.java b/rsocket-core/src/main/java/io/rsocket/frame/CancelFrameCodec.java similarity index 55% rename from rsocket-core/src/main/java/io/rsocket/frame/CancelFrameFlyweight.java rename to rsocket-core/src/main/java/io/rsocket/frame/CancelFrameCodec.java index 349a43c3a..d0d929f0f 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/CancelFrameFlyweight.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/CancelFrameCodec.java @@ -3,10 +3,10 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; -public class CancelFrameFlyweight { - private CancelFrameFlyweight() {} +public class CancelFrameCodec { + private CancelFrameCodec() {} public static ByteBuf encode(final ByteBufAllocator allocator, final int streamId) { - return FrameHeaderFlyweight.encode(allocator, streamId, FrameType.CANCEL, 0); + return FrameHeaderCodec.encode(allocator, streamId, FrameType.CANCEL, 0); } } diff --git a/rsocket-core/src/main/java/io/rsocket/frame/ErrorFrameFlyweight.java b/rsocket-core/src/main/java/io/rsocket/frame/ErrorFrameCodec.java similarity index 89% rename from rsocket-core/src/main/java/io/rsocket/frame/ErrorFrameFlyweight.java rename to rsocket-core/src/main/java/io/rsocket/frame/ErrorFrameCodec.java index ab26233f1..dcacb57dc 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/ErrorFrameFlyweight.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/ErrorFrameCodec.java @@ -6,7 +6,7 @@ import io.rsocket.RSocketErrorException; import java.nio.charset.StandardCharsets; -public class ErrorFrameFlyweight { +public class ErrorFrameCodec { // defined zero stream id error codes public static final int INVALID_SETUP = 0x00000001; @@ -26,7 +26,7 @@ public class ErrorFrameFlyweight { public static ByteBuf encode( ByteBufAllocator allocator, int streamId, Throwable t, ByteBuf data) { - ByteBuf header = FrameHeaderFlyweight.encode(allocator, streamId, FrameType.ERROR, 0); + ByteBuf header = FrameHeaderCodec.encode(allocator, streamId, FrameType.ERROR, 0); int errorCode = t instanceof RSocketErrorException @@ -46,7 +46,7 @@ public static ByteBuf encode(ByteBufAllocator allocator, int streamId, Throwable public static int errorCode(ByteBuf byteBuf) { byteBuf.markReaderIndex(); - byteBuf.skipBytes(FrameHeaderFlyweight.size()); + byteBuf.skipBytes(FrameHeaderCodec.size()); int i = byteBuf.readInt(); byteBuf.resetReaderIndex(); return i; @@ -54,7 +54,7 @@ public static int errorCode(ByteBuf byteBuf) { public static ByteBuf data(ByteBuf byteBuf) { byteBuf.markReaderIndex(); - byteBuf.skipBytes(FrameHeaderFlyweight.size() + Integer.BYTES); + byteBuf.skipBytes(FrameHeaderCodec.size() + Integer.BYTES); ByteBuf slice = byteBuf.slice(); byteBuf.resetReaderIndex(); return slice; diff --git a/rsocket-core/src/main/java/io/rsocket/frame/ErrorType.java b/rsocket-core/src/main/java/io/rsocket/frame/ErrorType.java deleted file mode 100644 index b41a5d59e..000000000 --- a/rsocket-core/src/main/java/io/rsocket/frame/ErrorType.java +++ /dev/null @@ -1,85 +0,0 @@ -package io.rsocket.frame; - -/** - * The types of {@link Error} that can be set. - * - * @see Error - * Codes - * @deprecated please use constants in {@link ErrorFrameFlyweight}. - */ -@Deprecated -public final class ErrorType { - - /** - * Application layer logic generating a Reactive Streams onError event. Stream ID MUST be > 0. - */ - public static final int APPLICATION_ERROR = 0x00000201; - - /** - * The Responder canceled the request but may have started processing it (similar to REJECTED but - * doesn't guarantee lack of side-effects). Stream ID MUST be > 0. - */ - public static final int CANCELED = 0x00000203; - - /** - * The connection is being terminated. Stream ID MUST be 0. Sender or Receiver of this frame MUST - * wait for outstanding streams to terminate before closing the connection. New requests MAY not - * be accepted. - */ - public static final int CONNECTION_CLOSE = 0x00000102; - - /** - * The connection is being terminated. Stream ID MUST be 0. Sender or Receiver of this frame MAY - * close the connection immediately without waiting for outstanding streams to terminate. - */ - public static final int CONNECTION_ERROR = 0x00000101; - - /** The request is invalid. Stream ID MUST be > 0. */ - public static final int INVALID = 0x00000204; - - /** - * The Setup frame is invalid for the server (it could be that the client is too recent for the - * old server). Stream ID MUST be 0. - */ - public static final int INVALID_SETUP = 0x00000001; - - /** - * Despite being a valid request, the Responder decided to reject it. The Responder guarantees - * that it didn't process the request. The reason for the rejection is explained in the Error Data - * section. Stream ID MUST be > 0. - */ - public static final int REJECTED = 0x00000202; - - /** - * The server rejected the resume, it can specify the reason in the payload. Stream ID MUST be 0. - */ - public static final int REJECTED_RESUME = 0x00000004; - - /** - * The server rejected the setup, it can specify the reason in the payload. Stream ID MUST be 0. - */ - public static final int REJECTED_SETUP = 0x00000003; - - /** Reserved. */ - public static final int RESERVED = 0x00000000; - - /** Reserved for Extension Use. */ - public static final int RESERVED_FOR_EXTENSION = 0xFFFFFFFF; - - /** - * Some (or all) of the parameters specified by the client are unsupported by the server. Stream - * ID MUST be 0. - */ - public static final int UNSUPPORTED_SETUP = 0x00000002; - - /** Minimum allowed user defined error code value */ - public static final int MIN_USER_ALLOWED_ERROR_CODE = 0x00000301; - - /** - * Maximum allowed user defined error code value. Note, the value is above signed integer maximum, - * so it will be negative after overflow. - */ - public static final int MAX_USER_ALLOWED_ERROR_CODE = 0xFFFFFFFE; - - private ErrorType() {} -} diff --git a/rsocket-core/src/main/java/io/rsocket/frame/ExtensionFrameCodec.java b/rsocket-core/src/main/java/io/rsocket/frame/ExtensionFrameCodec.java new file mode 100644 index 000000000..bf30b9556 --- /dev/null +++ b/rsocket-core/src/main/java/io/rsocket/frame/ExtensionFrameCodec.java @@ -0,0 +1,66 @@ +package io.rsocket.frame; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import javax.annotation.Nullable; + +public class ExtensionFrameCodec { + private ExtensionFrameCodec() {} + + public static ByteBuf encode( + ByteBufAllocator allocator, + int streamId, + int extendedType, + @Nullable ByteBuf metadata, + ByteBuf data) { + + final boolean hasMetadata = metadata != null; + + int flags = FrameHeaderCodec.FLAGS_I; + + if (hasMetadata) { + flags |= FrameHeaderCodec.FLAGS_M; + } + + final ByteBuf header = FrameHeaderCodec.encode(allocator, streamId, FrameType.EXT, flags); + header.writeInt(extendedType); + + return FrameBodyCodec.encode(allocator, header, metadata, hasMetadata, data); + } + + public static int extendedType(ByteBuf byteBuf) { + FrameHeaderCodec.ensureFrameType(FrameType.EXT, byteBuf); + byteBuf.markReaderIndex(); + byteBuf.skipBytes(FrameHeaderCodec.size()); + int i = byteBuf.readInt(); + byteBuf.resetReaderIndex(); + return i; + } + + public static ByteBuf data(ByteBuf byteBuf) { + FrameHeaderCodec.ensureFrameType(FrameType.EXT, byteBuf); + + boolean hasMetadata = FrameHeaderCodec.hasMetadata(byteBuf); + byteBuf.markReaderIndex(); + // Extended type + byteBuf.skipBytes(FrameHeaderCodec.size() + Integer.BYTES); + ByteBuf data = FrameBodyCodec.dataWithoutMarking(byteBuf, hasMetadata); + byteBuf.resetReaderIndex(); + return data; + } + + public static ByteBuf metadata(ByteBuf byteBuf) { + FrameHeaderCodec.ensureFrameType(FrameType.EXT, byteBuf); + + boolean hasMetadata = FrameHeaderCodec.hasMetadata(byteBuf); + if (!hasMetadata) { + return null; + } + byteBuf.markReaderIndex(); + // Extended type + byteBuf.skipBytes(FrameHeaderCodec.size() + Integer.BYTES); + ByteBuf metadata = FrameBodyCodec.metadataWithoutMarking(byteBuf); + byteBuf.resetReaderIndex(); + return metadata; + } +} diff --git a/rsocket-core/src/main/java/io/rsocket/frame/ExtensionFrameFlyweight.java b/rsocket-core/src/main/java/io/rsocket/frame/ExtensionFrameFlyweight.java deleted file mode 100644 index 8cb01b08f..000000000 --- a/rsocket-core/src/main/java/io/rsocket/frame/ExtensionFrameFlyweight.java +++ /dev/null @@ -1,66 +0,0 @@ -package io.rsocket.frame; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import javax.annotation.Nullable; - -public class ExtensionFrameFlyweight { - private ExtensionFrameFlyweight() {} - - public static ByteBuf encode( - ByteBufAllocator allocator, - int streamId, - int extendedType, - @Nullable ByteBuf metadata, - ByteBuf data) { - - final boolean hasMetadata = metadata != null; - - int flags = FrameHeaderFlyweight.FLAGS_I; - - if (hasMetadata) { - flags |= FrameHeaderFlyweight.FLAGS_M; - } - - final ByteBuf header = FrameHeaderFlyweight.encode(allocator, streamId, FrameType.EXT, flags); - header.writeInt(extendedType); - - return DataAndMetadataFlyweight.encode(allocator, header, metadata, hasMetadata, data); - } - - public static int extendedType(ByteBuf byteBuf) { - FrameHeaderFlyweight.ensureFrameType(FrameType.EXT, byteBuf); - byteBuf.markReaderIndex(); - byteBuf.skipBytes(FrameHeaderFlyweight.size()); - int i = byteBuf.readInt(); - byteBuf.resetReaderIndex(); - return i; - } - - public static ByteBuf data(ByteBuf byteBuf) { - FrameHeaderFlyweight.ensureFrameType(FrameType.EXT, byteBuf); - - boolean hasMetadata = FrameHeaderFlyweight.hasMetadata(byteBuf); - byteBuf.markReaderIndex(); - // Extended type - byteBuf.skipBytes(FrameHeaderFlyweight.size() + Integer.BYTES); - ByteBuf data = DataAndMetadataFlyweight.dataWithoutMarking(byteBuf, hasMetadata); - byteBuf.resetReaderIndex(); - return data; - } - - public static ByteBuf metadata(ByteBuf byteBuf) { - FrameHeaderFlyweight.ensureFrameType(FrameType.EXT, byteBuf); - - boolean hasMetadata = FrameHeaderFlyweight.hasMetadata(byteBuf); - if (!hasMetadata) { - return null; - } - byteBuf.markReaderIndex(); - // Extended type - byteBuf.skipBytes(FrameHeaderFlyweight.size() + Integer.BYTES); - ByteBuf metadata = DataAndMetadataFlyweight.metadataWithoutMarking(byteBuf); - byteBuf.resetReaderIndex(); - return metadata; - } -} diff --git a/rsocket-core/src/main/java/io/rsocket/frame/FragmentationFlyweight.java b/rsocket-core/src/main/java/io/rsocket/frame/FragmentationCodec.java similarity index 80% rename from rsocket-core/src/main/java/io/rsocket/frame/FragmentationFlyweight.java rename to rsocket-core/src/main/java/io/rsocket/frame/FragmentationCodec.java index a91d52782..de228b271 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/FragmentationFlyweight.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/FragmentationCodec.java @@ -5,7 +5,7 @@ import reactor.util.annotation.Nullable; /** FragmentationFlyweight is used to re-assemble frames */ -public class FragmentationFlyweight { +public class FragmentationCodec { public static ByteBuf encode(final ByteBufAllocator allocator, ByteBuf header, ByteBuf data) { return encode(allocator, header, null, data); } @@ -14,6 +14,6 @@ public static ByteBuf encode( final ByteBufAllocator allocator, ByteBuf header, @Nullable ByteBuf metadata, ByteBuf data) { final boolean hasMetadata = metadata != null; - return DataAndMetadataFlyweight.encode(allocator, header, metadata, hasMetadata, data); + return FrameBodyCodec.encode(allocator, header, metadata, hasMetadata, data); } } diff --git a/rsocket-core/src/main/java/io/rsocket/frame/DataAndMetadataFlyweight.java b/rsocket-core/src/main/java/io/rsocket/frame/FrameBodyCodec.java similarity index 97% rename from rsocket-core/src/main/java/io/rsocket/frame/DataAndMetadataFlyweight.java rename to rsocket-core/src/main/java/io/rsocket/frame/FrameBodyCodec.java index 73bfd38f1..3256d4426 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/DataAndMetadataFlyweight.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/FrameBodyCodec.java @@ -4,10 +4,10 @@ import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.Unpooled; -class DataAndMetadataFlyweight { +class FrameBodyCodec { public static final int FRAME_LENGTH_MASK = 0xFFFFFF; - private DataAndMetadataFlyweight() {} + private FrameBodyCodec() {} private static void encodeLength(final ByteBuf byteBuf, final int length) { if ((length & ~FRAME_LENGTH_MASK) != 0) { diff --git a/rsocket-core/src/main/java/io/rsocket/frame/FrameHeaderFlyweight.java b/rsocket-core/src/main/java/io/rsocket/frame/FrameHeaderCodec.java similarity index 98% rename from rsocket-core/src/main/java/io/rsocket/frame/FrameHeaderFlyweight.java rename to rsocket-core/src/main/java/io/rsocket/frame/FrameHeaderCodec.java index cbc677444..28f39459d 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/FrameHeaderFlyweight.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/FrameHeaderCodec.java @@ -12,7 +12,7 @@ * *

Not thread-safe. Assumed to be used single-threaded */ -public final class FrameHeaderFlyweight { +public final class FrameHeaderCodec { /** (I)gnore flag: a value of 0 indicates the protocol can't ignore this frame */ public static final int FLAGS_I = 0b10_0000_0000; /** (M)etadata flag: a value of 1 indicates the frame contains metadata */ @@ -38,7 +38,7 @@ public final class FrameHeaderFlyweight { disableFrameTypeCheck = Boolean.getBoolean(DISABLE_FRAME_TYPE_CHECK); } - private FrameHeaderFlyweight() {} + private FrameHeaderCodec() {} static ByteBuf encodeStreamZero( final ByteBufAllocator allocator, final FrameType frameType, int flags) { diff --git a/rsocket-core/src/main/java/io/rsocket/frame/FrameLengthFlyweight.java b/rsocket-core/src/main/java/io/rsocket/frame/FrameLengthCodec.java similarity index 95% rename from rsocket-core/src/main/java/io/rsocket/frame/FrameLengthFlyweight.java rename to rsocket-core/src/main/java/io/rsocket/frame/FrameLengthCodec.java index 622160061..f6c19c8ee 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/FrameLengthFlyweight.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/FrameLengthCodec.java @@ -7,11 +7,11 @@ * Some transports like TCP aren't framed, and require a length. This is used by DuplexConnections * for transports that need to send length */ -public class FrameLengthFlyweight { +public class FrameLengthCodec { public static final int FRAME_LENGTH_MASK = 0xFFFFFF; public static final int FRAME_LENGTH_SIZE = 3; - private FrameLengthFlyweight() {} + private FrameLengthCodec() {} private static void encodeLength(final ByteBuf byteBuf, final int length) { if ((length & ~FRAME_LENGTH_MASK) != 0) { diff --git a/rsocket-core/src/main/java/io/rsocket/frame/FrameUtil.java b/rsocket-core/src/main/java/io/rsocket/frame/FrameUtil.java index 6662d34af..66d18c8a7 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/FrameUtil.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/FrameUtil.java @@ -9,8 +9,8 @@ public class FrameUtil { private FrameUtil() {} public static String toString(ByteBuf frame) { - FrameType frameType = FrameHeaderFlyweight.frameType(frame); - int streamId = FrameHeaderFlyweight.streamId(frame); + FrameType frameType = FrameHeaderCodec.frameType(frame); + int streamId = FrameHeaderCodec.streamId(frame); StringBuilder payload = new StringBuilder(); payload @@ -19,20 +19,18 @@ public static String toString(ByteBuf frame) { .append(" Type: ") .append(frameType) .append(" Flags: 0b") - .append(Integer.toBinaryString(FrameHeaderFlyweight.flags(frame))) + .append(Integer.toBinaryString(FrameHeaderCodec.flags(frame))) .append(" Length: " + frame.readableBytes()); if (frameType.hasInitialRequestN()) { - payload - .append(" InitialRequestN: ") - .append(RequestStreamFrameFlyweight.initialRequestN(frame)); + payload.append(" InitialRequestN: ").append(RequestStreamFrameCodec.initialRequestN(frame)); } if (frameType == FrameType.REQUEST_N) { - payload.append(" RequestN: ").append(RequestNFrameFlyweight.requestN(frame)); + payload.append(" RequestN: ").append(RequestNFrameCodec.requestN(frame)); } - if (FrameHeaderFlyweight.hasMetadata(frame)) { + if (FrameHeaderCodec.hasMetadata(frame)) { payload.append("\nMetadata:\n"); ByteBufUtil.appendPrettyHexDump(payload, getMetadata(frame, frameType)); @@ -45,37 +43,37 @@ public static String toString(ByteBuf frame) { } private static ByteBuf getMetadata(ByteBuf frame, FrameType frameType) { - boolean hasMetadata = FrameHeaderFlyweight.hasMetadata(frame); + boolean hasMetadata = FrameHeaderCodec.hasMetadata(frame); if (hasMetadata) { ByteBuf metadata; switch (frameType) { case REQUEST_FNF: - metadata = RequestFireAndForgetFrameFlyweight.metadata(frame); + metadata = RequestFireAndForgetFrameCodec.metadata(frame); break; case REQUEST_STREAM: - metadata = RequestStreamFrameFlyweight.metadata(frame); + metadata = RequestStreamFrameCodec.metadata(frame); break; case REQUEST_RESPONSE: - metadata = RequestResponseFrameFlyweight.metadata(frame); + metadata = RequestResponseFrameCodec.metadata(frame); break; case REQUEST_CHANNEL: - metadata = RequestChannelFrameFlyweight.metadata(frame); + metadata = RequestChannelFrameCodec.metadata(frame); break; // Payload and synthetic types case PAYLOAD: case NEXT: case NEXT_COMPLETE: case COMPLETE: - metadata = PayloadFrameFlyweight.metadata(frame); + metadata = PayloadFrameCodec.metadata(frame); break; case METADATA_PUSH: - metadata = MetadataPushFrameFlyweight.metadata(frame); + metadata = MetadataPushFrameCodec.metadata(frame); break; case SETUP: - metadata = SetupFrameFlyweight.metadata(frame); + metadata = SetupFrameCodec.metadata(frame); break; case LEASE: - metadata = LeaseFrameFlyweight.metadata(frame); + metadata = LeaseFrameCodec.metadata(frame); break; default: return Unpooled.EMPTY_BUFFER; @@ -90,26 +88,26 @@ private static ByteBuf getData(ByteBuf frame, FrameType frameType) { ByteBuf data; switch (frameType) { case REQUEST_FNF: - data = RequestFireAndForgetFrameFlyweight.data(frame); + data = RequestFireAndForgetFrameCodec.data(frame); break; case REQUEST_STREAM: - data = RequestStreamFrameFlyweight.data(frame); + data = RequestStreamFrameCodec.data(frame); break; case REQUEST_RESPONSE: - data = RequestResponseFrameFlyweight.data(frame); + data = RequestResponseFrameCodec.data(frame); break; case REQUEST_CHANNEL: - data = RequestChannelFrameFlyweight.data(frame); + data = RequestChannelFrameCodec.data(frame); break; // Payload and synthetic types case PAYLOAD: case NEXT: case NEXT_COMPLETE: case COMPLETE: - data = PayloadFrameFlyweight.data(frame); + data = PayloadFrameCodec.data(frame); break; case SETUP: - data = SetupFrameFlyweight.data(frame); + data = SetupFrameCodec.data(frame); break; default: return Unpooled.EMPTY_BUFFER; diff --git a/rsocket-core/src/main/java/io/rsocket/frame/GenericFrameCodec.java b/rsocket-core/src/main/java/io/rsocket/frame/GenericFrameCodec.java new file mode 100644 index 000000000..65e7eeeea --- /dev/null +++ b/rsocket-core/src/main/java/io/rsocket/frame/GenericFrameCodec.java @@ -0,0 +1,157 @@ +package io.rsocket.frame; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.util.IllegalReferenceCountException; +import io.rsocket.Payload; +import javax.annotation.Nullable; + +class GenericFrameCodec { + + static ByteBuf encodeReleasingPayload( + final ByteBufAllocator allocator, + final FrameType frameType, + final int streamId, + boolean complete, + boolean next, + final Payload payload) { + return encodeReleasingPayload(allocator, frameType, streamId, complete, next, 0, payload); + } + + static ByteBuf encodeReleasingPayload( + final ByteBufAllocator allocator, + final FrameType frameType, + final int streamId, + boolean complete, + boolean next, + int requestN, + final Payload payload) { + + // if refCnt exceptions throws here it is safe to do no-op + boolean hasMetadata = payload.hasMetadata(); + // if refCnt exceptions throws here it is safe to do no-op still + final ByteBuf metadata = hasMetadata ? payload.metadata().retain() : null; + final ByteBuf data; + // retaining data safely. May throw either NPE or RefCntE + try { + data = payload.data().retain(); + } catch (IllegalReferenceCountException | NullPointerException e) { + if (hasMetadata) { + metadata.release(); + } + throw e; + } + // releasing payload safely since it can be already released wheres we have to release retained + // data and metadata as well + try { + payload.release(); + } catch (IllegalReferenceCountException e) { + data.release(); + if (hasMetadata) { + metadata.release(); + } + throw e; + } + + return encode(allocator, frameType, streamId, false, complete, next, requestN, metadata, data); + } + + static ByteBuf encode( + final ByteBufAllocator allocator, + final FrameType frameType, + final int streamId, + boolean fragmentFollows, + @Nullable ByteBuf metadata, + ByteBuf data) { + return encode(allocator, frameType, streamId, fragmentFollows, false, false, 0, metadata, data); + } + + static ByteBuf encode( + final ByteBufAllocator allocator, + final FrameType frameType, + final int streamId, + boolean fragmentFollows, + boolean complete, + boolean next, + int requestN, + @Nullable ByteBuf metadata, + ByteBuf data) { + + final boolean hasMetadata = metadata != null; + + int flags = 0; + + if (hasMetadata) { + flags |= FrameHeaderCodec.FLAGS_M; + } + + if (fragmentFollows) { + flags |= FrameHeaderCodec.FLAGS_F; + } + + if (complete) { + flags |= FrameHeaderCodec.FLAGS_C; + } + + if (next) { + flags |= FrameHeaderCodec.FLAGS_N; + } + + final ByteBuf header = FrameHeaderCodec.encode(allocator, streamId, frameType, flags); + + if (requestN > 0) { + header.writeInt(requestN); + } + + return FrameBodyCodec.encode(allocator, header, metadata, hasMetadata, data); + } + + static ByteBuf data(ByteBuf byteBuf) { + boolean hasMetadata = FrameHeaderCodec.hasMetadata(byteBuf); + int idx = byteBuf.readerIndex(); + byteBuf.skipBytes(FrameHeaderCodec.size()); + ByteBuf data = FrameBodyCodec.dataWithoutMarking(byteBuf, hasMetadata); + byteBuf.readerIndex(idx); + return data; + } + + static ByteBuf metadata(ByteBuf byteBuf) { + boolean hasMetadata = FrameHeaderCodec.hasMetadata(byteBuf); + if (!hasMetadata) { + return null; + } + byteBuf.markReaderIndex(); + byteBuf.skipBytes(FrameHeaderCodec.size()); + ByteBuf metadata = FrameBodyCodec.metadataWithoutMarking(byteBuf); + byteBuf.resetReaderIndex(); + return metadata; + } + + static ByteBuf dataWithRequestN(ByteBuf byteBuf) { + boolean hasMetadata = FrameHeaderCodec.hasMetadata(byteBuf); + byteBuf.markReaderIndex(); + byteBuf.skipBytes(FrameHeaderCodec.size() + Integer.BYTES); + ByteBuf data = FrameBodyCodec.dataWithoutMarking(byteBuf, hasMetadata); + byteBuf.resetReaderIndex(); + return data; + } + + static ByteBuf metadataWithRequestN(ByteBuf byteBuf) { + boolean hasMetadata = FrameHeaderCodec.hasMetadata(byteBuf); + if (!hasMetadata) { + return null; + } + byteBuf.markReaderIndex(); + byteBuf.skipBytes(FrameHeaderCodec.size() + Integer.BYTES); + ByteBuf metadata = FrameBodyCodec.metadataWithoutMarking(byteBuf); + byteBuf.resetReaderIndex(); + return metadata; + } + + static int initialRequestN(ByteBuf byteBuf) { + byteBuf.markReaderIndex(); + int i = byteBuf.skipBytes(FrameHeaderCodec.size()).readInt(); + byteBuf.resetReaderIndex(); + return i; + } +} diff --git a/rsocket-core/src/main/java/io/rsocket/frame/KeepAliveFrameFlyweight.java b/rsocket-core/src/main/java/io/rsocket/frame/KeepAliveFrameCodec.java similarity index 61% rename from rsocket-core/src/main/java/io/rsocket/frame/KeepAliveFrameFlyweight.java rename to rsocket-core/src/main/java/io/rsocket/frame/KeepAliveFrameCodec.java index b591412a6..752d5b3eb 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/KeepAliveFrameFlyweight.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/KeepAliveFrameCodec.java @@ -3,7 +3,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; -public class KeepAliveFrameFlyweight { +public class KeepAliveFrameCodec { /** * (R)espond: Set by the sender of the KEEPALIVE, to which the responder MUST reply with a * KEEPALIVE without the R flag set @@ -12,7 +12,7 @@ public class KeepAliveFrameFlyweight { public static final long LAST_POSITION_MASK = 0x8000000000000000L; - private KeepAliveFrameFlyweight() {} + private KeepAliveFrameCodec() {} public static ByteBuf encode( final ByteBufAllocator allocator, @@ -20,7 +20,7 @@ public static ByteBuf encode( final long lastPosition, final ByteBuf data) { final int flags = respond ? FLAGS_KEEPALIVE_R : 0; - ByteBuf header = FrameHeaderFlyweight.encodeStreamZero(allocator, FrameType.KEEPALIVE, flags); + ByteBuf header = FrameHeaderCodec.encodeStreamZero(allocator, FrameType.KEEPALIVE, flags); long lp = 0; if (lastPosition > 0) { @@ -29,27 +29,27 @@ public static ByteBuf encode( header.writeLong(lp); - return DataAndMetadataFlyweight.encode(allocator, header, null, false, data); + return FrameBodyCodec.encode(allocator, header, null, false, data); } public static boolean respondFlag(ByteBuf byteBuf) { - FrameHeaderFlyweight.ensureFrameType(FrameType.KEEPALIVE, byteBuf); - int flags = FrameHeaderFlyweight.flags(byteBuf); + FrameHeaderCodec.ensureFrameType(FrameType.KEEPALIVE, byteBuf); + int flags = FrameHeaderCodec.flags(byteBuf); return (flags & FLAGS_KEEPALIVE_R) == FLAGS_KEEPALIVE_R; } public static long lastPosition(ByteBuf byteBuf) { - FrameHeaderFlyweight.ensureFrameType(FrameType.KEEPALIVE, byteBuf); + FrameHeaderCodec.ensureFrameType(FrameType.KEEPALIVE, byteBuf); byteBuf.markReaderIndex(); - long l = byteBuf.skipBytes(FrameHeaderFlyweight.size()).readLong(); + long l = byteBuf.skipBytes(FrameHeaderCodec.size()).readLong(); byteBuf.resetReaderIndex(); return l; } public static ByteBuf data(ByteBuf byteBuf) { - FrameHeaderFlyweight.ensureFrameType(FrameType.KEEPALIVE, byteBuf); + FrameHeaderCodec.ensureFrameType(FrameType.KEEPALIVE, byteBuf); byteBuf.markReaderIndex(); - ByteBuf slice = byteBuf.skipBytes(FrameHeaderFlyweight.size() + Long.BYTES).slice(); + ByteBuf slice = byteBuf.skipBytes(FrameHeaderCodec.size() + Long.BYTES).slice(); byteBuf.resetReaderIndex(); return slice; } diff --git a/rsocket-core/src/main/java/io/rsocket/frame/LeaseFrameFlyweight.java b/rsocket-core/src/main/java/io/rsocket/frame/LeaseFrameCodec.java similarity index 74% rename from rsocket-core/src/main/java/io/rsocket/frame/LeaseFrameFlyweight.java rename to rsocket-core/src/main/java/io/rsocket/frame/LeaseFrameCodec.java index 32f086a15..cafd80104 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/LeaseFrameFlyweight.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/LeaseFrameCodec.java @@ -5,7 +5,7 @@ import io.netty.buffer.Unpooled; import javax.annotation.Nullable; -public class LeaseFrameFlyweight { +public class LeaseFrameCodec { public static ByteBuf encode( final ByteBufAllocator allocator, @@ -18,11 +18,11 @@ public static ByteBuf encode( int flags = 0; if (hasMetadata) { - flags |= FrameHeaderFlyweight.FLAGS_M; + flags |= FrameHeaderCodec.FLAGS_M; } final ByteBuf header = - FrameHeaderFlyweight.encodeStreamZero(allocator, FrameType.LEASE, flags) + FrameHeaderCodec.encodeStreamZero(allocator, FrameType.LEASE, flags) .writeInt(ttl) .writeInt(numRequests); @@ -49,30 +49,30 @@ public static ByteBuf encode( } public static int ttl(final ByteBuf byteBuf) { - FrameHeaderFlyweight.ensureFrameType(FrameType.LEASE, byteBuf); + FrameHeaderCodec.ensureFrameType(FrameType.LEASE, byteBuf); byteBuf.markReaderIndex(); - byteBuf.skipBytes(FrameHeaderFlyweight.size()); + byteBuf.skipBytes(FrameHeaderCodec.size()); int ttl = byteBuf.readInt(); byteBuf.resetReaderIndex(); return ttl; } public static int numRequests(final ByteBuf byteBuf) { - FrameHeaderFlyweight.ensureFrameType(FrameType.LEASE, byteBuf); + FrameHeaderCodec.ensureFrameType(FrameType.LEASE, byteBuf); byteBuf.markReaderIndex(); // Ttl - byteBuf.skipBytes(FrameHeaderFlyweight.size() + Integer.BYTES); + byteBuf.skipBytes(FrameHeaderCodec.size() + Integer.BYTES); int numRequests = byteBuf.readInt(); byteBuf.resetReaderIndex(); return numRequests; } public static ByteBuf metadata(final ByteBuf byteBuf) { - FrameHeaderFlyweight.ensureFrameType(FrameType.LEASE, byteBuf); - if (FrameHeaderFlyweight.hasMetadata(byteBuf)) { + FrameHeaderCodec.ensureFrameType(FrameType.LEASE, byteBuf); + if (FrameHeaderCodec.hasMetadata(byteBuf)) { byteBuf.markReaderIndex(); // Ttl + Num of requests - byteBuf.skipBytes(FrameHeaderFlyweight.size() + Integer.BYTES * 2); + byteBuf.skipBytes(FrameHeaderCodec.size() + Integer.BYTES * 2); ByteBuf metadata = byteBuf.slice(); byteBuf.resetReaderIndex(); return metadata; diff --git a/rsocket-core/src/main/java/io/rsocket/frame/MetadataPushFrameFlyweight.java b/rsocket-core/src/main/java/io/rsocket/frame/MetadataPushFrameCodec.java similarity index 83% rename from rsocket-core/src/main/java/io/rsocket/frame/MetadataPushFrameFlyweight.java rename to rsocket-core/src/main/java/io/rsocket/frame/MetadataPushFrameCodec.java index a39acef92..62c8a17dc 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/MetadataPushFrameFlyweight.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/MetadataPushFrameCodec.java @@ -5,7 +5,7 @@ import io.netty.util.IllegalReferenceCountException; import io.rsocket.Payload; -public class MetadataPushFrameFlyweight { +public class MetadataPushFrameCodec { public static ByteBuf encodeReleasingPayload(ByteBufAllocator allocator, Payload payload) { final ByteBuf metadata = payload.metadata().retain(); @@ -22,14 +22,14 @@ public static ByteBuf encodeReleasingPayload(ByteBufAllocator allocator, Payload public static ByteBuf encode(ByteBufAllocator allocator, ByteBuf metadata) { ByteBuf header = - FrameHeaderFlyweight.encodeStreamZero( - allocator, FrameType.METADATA_PUSH, FrameHeaderFlyweight.FLAGS_M); + FrameHeaderCodec.encodeStreamZero( + allocator, FrameType.METADATA_PUSH, FrameHeaderCodec.FLAGS_M); return allocator.compositeBuffer(2).addComponents(true, header, metadata); } public static ByteBuf metadata(ByteBuf byteBuf) { byteBuf.markReaderIndex(); - int headerSize = FrameHeaderFlyweight.size(); + int headerSize = FrameHeaderCodec.size(); int metadataLength = byteBuf.readableBytes() - headerSize; byteBuf.skipBytes(headerSize); ByteBuf metadata = byteBuf.readSlice(metadataLength); diff --git a/rsocket-core/src/main/java/io/rsocket/frame/PayloadFrameCodec.java b/rsocket-core/src/main/java/io/rsocket/frame/PayloadFrameCodec.java new file mode 100644 index 000000000..8a7e6427a --- /dev/null +++ b/rsocket-core/src/main/java/io/rsocket/frame/PayloadFrameCodec.java @@ -0,0 +1,54 @@ +package io.rsocket.frame; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.rsocket.Payload; + +public class PayloadFrameCodec { + + private PayloadFrameCodec() {} + + public static ByteBuf encodeNextReleasingPayload( + ByteBufAllocator allocator, int streamId, Payload payload) { + + return encodeReleasingPayload(allocator, streamId, false, payload); + } + + public static ByteBuf encodeNextCompleteReleasingPayload( + ByteBufAllocator allocator, int streamId, Payload payload) { + + return encodeReleasingPayload(allocator, streamId, true, payload); + } + + static ByteBuf encodeReleasingPayload( + ByteBufAllocator allocator, int streamId, boolean complete, Payload payload) { + + return GenericFrameCodec.encodeReleasingPayload( + allocator, FrameType.PAYLOAD, streamId, complete, true, payload); + } + + public static ByteBuf encodeComplete(ByteBufAllocator allocator, int streamId) { + return encode(allocator, streamId, false, true, false, null, null); + } + + public static ByteBuf encode( + ByteBufAllocator allocator, + int streamId, + boolean fragmentFollows, + boolean complete, + boolean next, + ByteBuf metadata, + ByteBuf data) { + + return GenericFrameCodec.encode( + allocator, FrameType.PAYLOAD, streamId, fragmentFollows, complete, next, 0, metadata, data); + } + + public static ByteBuf data(ByteBuf byteBuf) { + return GenericFrameCodec.data(byteBuf); + } + + public static ByteBuf metadata(ByteBuf byteBuf) { + return GenericFrameCodec.metadata(byteBuf); + } +} diff --git a/rsocket-core/src/main/java/io/rsocket/frame/PayloadFrameFlyweight.java b/rsocket-core/src/main/java/io/rsocket/frame/PayloadFrameFlyweight.java deleted file mode 100644 index 53ac6150b..000000000 --- a/rsocket-core/src/main/java/io/rsocket/frame/PayloadFrameFlyweight.java +++ /dev/null @@ -1,79 +0,0 @@ -package io.rsocket.frame; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.util.IllegalReferenceCountException; -import io.rsocket.Payload; - -public class PayloadFrameFlyweight { - private static final RequestFlyweight FLYWEIGHT = new RequestFlyweight(FrameType.PAYLOAD); - - private PayloadFrameFlyweight() {} - - public static ByteBuf encodeNextReleasingPayload( - ByteBufAllocator allocator, int streamId, Payload payload) { - return encodeReleasingPayload(allocator, streamId, false, payload); - } - - public static ByteBuf encodeNextCompleteReleasingPayload( - ByteBufAllocator allocator, int streamId, Payload payload) { - - return encodeReleasingPayload(allocator, streamId, true, payload); - } - - static ByteBuf encodeReleasingPayload( - ByteBufAllocator allocator, int streamId, boolean complete, Payload payload) { - - // if refCnt exceptions throws here it is safe to do no-op - boolean hasMetadata = payload.hasMetadata(); - // if refCnt exceptions throws here it is safe to do no-op still - final ByteBuf metadata = hasMetadata ? payload.metadata().retain() : null; - final ByteBuf data; - // retaining data safely. May throw either NPE or RefCntE - try { - data = payload.data().retain(); - } catch (IllegalReferenceCountException | NullPointerException e) { - if (hasMetadata) { - metadata.release(); - } - throw e; - } - // releasing payload safely since it can be already released wheres we have to release retained - // data and metadata as well - try { - payload.release(); - } catch (IllegalReferenceCountException e) { - data.release(); - if (hasMetadata) { - metadata.release(); - } - throw e; - } - - return encode(allocator, streamId, false, complete, true, metadata, data); - } - - public static ByteBuf encodeComplete(ByteBufAllocator allocator, int streamId) { - return encode(allocator, streamId, false, true, false, null, null); - } - - public static ByteBuf encode( - ByteBufAllocator allocator, - int streamId, - boolean fragmentFollows, - boolean complete, - boolean next, - ByteBuf metadata, - ByteBuf data) { - return FLYWEIGHT.encode( - allocator, streamId, fragmentFollows, complete, next, 0, metadata, data); - } - - public static ByteBuf data(ByteBuf byteBuf) { - return FLYWEIGHT.data(byteBuf); - } - - public static ByteBuf metadata(ByteBuf byteBuf) { - return FLYWEIGHT.metadata(byteBuf); - } -} diff --git a/rsocket-core/src/main/java/io/rsocket/frame/RequestChannelFrameCodec.java b/rsocket-core/src/main/java/io/rsocket/frame/RequestChannelFrameCodec.java new file mode 100644 index 000000000..2ff887043 --- /dev/null +++ b/rsocket-core/src/main/java/io/rsocket/frame/RequestChannelFrameCodec.java @@ -0,0 +1,67 @@ +package io.rsocket.frame; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.rsocket.Payload; + +public class RequestChannelFrameCodec { + + private RequestChannelFrameCodec() {} + + public static ByteBuf encodeReleasingPayload( + ByteBufAllocator allocator, + int streamId, + boolean complete, + long initialRequestN, + Payload payload) { + + if (initialRequestN < 1) { + throw new IllegalArgumentException("request n is less than 1"); + } + + int reqN = initialRequestN > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) initialRequestN; + + return GenericFrameCodec.encodeReleasingPayload( + allocator, FrameType.REQUEST_CHANNEL, streamId, complete, false, reqN, payload); + } + + public static ByteBuf encode( + ByteBufAllocator allocator, + int streamId, + boolean fragmentFollows, + boolean complete, + long initialRequestN, + ByteBuf metadata, + ByteBuf data) { + + if (initialRequestN < 1) { + throw new IllegalArgumentException("request n is less than 1"); + } + + int reqN = initialRequestN > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) initialRequestN; + + return GenericFrameCodec.encode( + allocator, + FrameType.REQUEST_CHANNEL, + streamId, + fragmentFollows, + complete, + false, + reqN, + metadata, + data); + } + + public static ByteBuf data(ByteBuf byteBuf) { + return GenericFrameCodec.dataWithRequestN(byteBuf); + } + + public static ByteBuf metadata(ByteBuf byteBuf) { + return GenericFrameCodec.metadataWithRequestN(byteBuf); + } + + public static long initialRequestN(ByteBuf byteBuf) { + int requestN = GenericFrameCodec.initialRequestN(byteBuf); + return requestN == Integer.MAX_VALUE ? Long.MAX_VALUE : requestN; + } +} diff --git a/rsocket-core/src/main/java/io/rsocket/frame/RequestChannelFrameFlyweight.java b/rsocket-core/src/main/java/io/rsocket/frame/RequestChannelFrameFlyweight.java deleted file mode 100644 index c0db21170..000000000 --- a/rsocket-core/src/main/java/io/rsocket/frame/RequestChannelFrameFlyweight.java +++ /dev/null @@ -1,81 +0,0 @@ -package io.rsocket.frame; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.util.IllegalReferenceCountException; -import io.rsocket.Payload; - -public class RequestChannelFrameFlyweight { - - private static final RequestFlyweight FLYWEIGHT = new RequestFlyweight(FrameType.REQUEST_CHANNEL); - - private RequestChannelFrameFlyweight() {} - - public static ByteBuf encodeReleasingPayload( - ByteBufAllocator allocator, - int streamId, - boolean complete, - long initialRequestN, - Payload payload) { - - // if refCnt exceptions throws here it is safe to do no-op - boolean hasMetadata = payload.hasMetadata(); - // if refCnt exceptions throws here it is safe to do no-op still - final ByteBuf metadata = hasMetadata ? payload.metadata().retain() : null; - final ByteBuf data; - // retaining data safely. May throw either NPE or RefCntE - try { - data = payload.data().retain(); - } catch (IllegalReferenceCountException | NullPointerException e) { - if (hasMetadata) { - metadata.release(); - } - throw e; - } - // releasing payload safely since it can be already released wheres we have to release retained - // data and metadata as well - try { - payload.release(); - } catch (IllegalReferenceCountException e) { - data.release(); - if (hasMetadata) { - metadata.release(); - } - throw e; - } - - return encode(allocator, streamId, false, complete, initialRequestN, metadata, data); - } - - public static ByteBuf encode( - ByteBufAllocator allocator, - int streamId, - boolean fragmentFollows, - boolean complete, - long initialRequestN, - ByteBuf metadata, - ByteBuf data) { - - if (initialRequestN < 1) { - throw new IllegalArgumentException("request n is less than 1"); - } - - int reqN = initialRequestN > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) initialRequestN; - - return FLYWEIGHT.encode( - allocator, streamId, fragmentFollows, complete, false, reqN, metadata, data); - } - - public static ByteBuf data(ByteBuf byteBuf) { - return FLYWEIGHT.dataWithRequestN(byteBuf); - } - - public static ByteBuf metadata(ByteBuf byteBuf) { - return FLYWEIGHT.metadataWithRequestN(byteBuf); - } - - public static long initialRequestN(ByteBuf byteBuf) { - int requestN = FLYWEIGHT.initialRequestN(byteBuf); - return requestN == Integer.MAX_VALUE ? Long.MAX_VALUE : requestN; - } -} diff --git a/rsocket-core/src/main/java/io/rsocket/frame/RequestFireAndForgetFrameCodec.java b/rsocket-core/src/main/java/io/rsocket/frame/RequestFireAndForgetFrameCodec.java new file mode 100644 index 000000000..ddb5bc5d7 --- /dev/null +++ b/rsocket-core/src/main/java/io/rsocket/frame/RequestFireAndForgetFrameCodec.java @@ -0,0 +1,36 @@ +package io.rsocket.frame; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.rsocket.Payload; + +public class RequestFireAndForgetFrameCodec { + + private RequestFireAndForgetFrameCodec() {} + + public static ByteBuf encodeReleasingPayload( + ByteBufAllocator allocator, int streamId, Payload payload) { + + return GenericFrameCodec.encodeReleasingPayload( + allocator, FrameType.REQUEST_FNF, streamId, false, false, payload); + } + + public static ByteBuf encode( + ByteBufAllocator allocator, + int streamId, + boolean fragmentFollows, + ByteBuf metadata, + ByteBuf data) { + + return GenericFrameCodec.encode( + allocator, FrameType.REQUEST_FNF, streamId, fragmentFollows, metadata, data); + } + + public static ByteBuf data(ByteBuf byteBuf) { + return GenericFrameCodec.data(byteBuf); + } + + public static ByteBuf metadata(ByteBuf byteBuf) { + return GenericFrameCodec.metadata(byteBuf); + } +} diff --git a/rsocket-core/src/main/java/io/rsocket/frame/RequestFireAndForgetFrameFlyweight.java b/rsocket-core/src/main/java/io/rsocket/frame/RequestFireAndForgetFrameFlyweight.java deleted file mode 100644 index e091edcc3..000000000 --- a/rsocket-core/src/main/java/io/rsocket/frame/RequestFireAndForgetFrameFlyweight.java +++ /dev/null @@ -1,63 +0,0 @@ -package io.rsocket.frame; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.util.IllegalReferenceCountException; -import io.rsocket.Payload; - -public class RequestFireAndForgetFrameFlyweight { - - private static final RequestFlyweight FLYWEIGHT = new RequestFlyweight(FrameType.REQUEST_FNF); - - private RequestFireAndForgetFrameFlyweight() {} - - public static ByteBuf encodeReleasingPayload( - ByteBufAllocator allocator, int streamId, Payload payload) { - - // if refCnt exceptions throws here it is safe to do no-op - boolean hasMetadata = payload.hasMetadata(); - // if refCnt exceptions throws here it is safe to do no-op still - final ByteBuf metadata = hasMetadata ? payload.metadata().retain() : null; - final ByteBuf data; - // retaining data safely. May throw either NPE or RefCntE - try { - data = payload.data().retain(); - } catch (IllegalReferenceCountException | NullPointerException e) { - if (hasMetadata) { - metadata.release(); - } - throw e; - } - // releasing payload safely since it can be already released wheres we have to release retained - // data and metadata as well - try { - payload.release(); - } catch (IllegalReferenceCountException e) { - data.release(); - if (hasMetadata) { - metadata.release(); - } - throw e; - } - - return FLYWEIGHT.encode(allocator, streamId, false, metadata, data); - } - - public static ByteBuf encode( - ByteBufAllocator allocator, - int streamId, - boolean fragmentFollows, - ByteBuf metadata, - ByteBuf data) { - - return FLYWEIGHT.encode(allocator, streamId, fragmentFollows, metadata, data); - } - - public static ByteBuf data(ByteBuf byteBuf) { - return FLYWEIGHT.data(byteBuf); - } - - public static ByteBuf metadata(ByteBuf byteBuf) { - return FLYWEIGHT.metadata(byteBuf); - } -} diff --git a/rsocket-core/src/main/java/io/rsocket/frame/RequestFlyweight.java b/rsocket-core/src/main/java/io/rsocket/frame/RequestFlyweight.java deleted file mode 100644 index 15fac9f55..000000000 --- a/rsocket-core/src/main/java/io/rsocket/frame/RequestFlyweight.java +++ /dev/null @@ -1,110 +0,0 @@ -package io.rsocket.frame; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import javax.annotation.Nullable; - -class RequestFlyweight { - FrameType frameType; - - RequestFlyweight(FrameType frameType) { - this.frameType = frameType; - } - - ByteBuf encode( - final ByteBufAllocator allocator, - final int streamId, - boolean fragmentFollows, - @Nullable ByteBuf metadata, - ByteBuf data) { - return encode(allocator, streamId, fragmentFollows, false, false, 0, metadata, data); - } - - ByteBuf encode( - final ByteBufAllocator allocator, - final int streamId, - boolean fragmentFollows, - boolean complete, - boolean next, - int requestN, - @Nullable ByteBuf metadata, - ByteBuf data) { - - final boolean hasMetadata = metadata != null; - - int flags = 0; - - if (hasMetadata) { - flags |= FrameHeaderFlyweight.FLAGS_M; - } - - if (fragmentFollows) { - flags |= FrameHeaderFlyweight.FLAGS_F; - } - - if (complete) { - flags |= FrameHeaderFlyweight.FLAGS_C; - } - - if (next) { - flags |= FrameHeaderFlyweight.FLAGS_N; - } - - final ByteBuf header = FrameHeaderFlyweight.encode(allocator, streamId, frameType, flags); - - if (requestN > 0) { - header.writeInt(requestN); - } - - return DataAndMetadataFlyweight.encode(allocator, header, metadata, hasMetadata, data); - } - - ByteBuf data(ByteBuf byteBuf) { - boolean hasMetadata = FrameHeaderFlyweight.hasMetadata(byteBuf); - int idx = byteBuf.readerIndex(); - byteBuf.skipBytes(FrameHeaderFlyweight.size()); - ByteBuf data = DataAndMetadataFlyweight.dataWithoutMarking(byteBuf, hasMetadata); - byteBuf.readerIndex(idx); - return data; - } - - ByteBuf metadata(ByteBuf byteBuf) { - boolean hasMetadata = FrameHeaderFlyweight.hasMetadata(byteBuf); - if (!hasMetadata) { - return null; - } - byteBuf.markReaderIndex(); - byteBuf.skipBytes(FrameHeaderFlyweight.size()); - ByteBuf metadata = DataAndMetadataFlyweight.metadataWithoutMarking(byteBuf); - byteBuf.resetReaderIndex(); - return metadata; - } - - ByteBuf dataWithRequestN(ByteBuf byteBuf) { - boolean hasMetadata = FrameHeaderFlyweight.hasMetadata(byteBuf); - byteBuf.markReaderIndex(); - byteBuf.skipBytes(FrameHeaderFlyweight.size() + Integer.BYTES); - ByteBuf data = DataAndMetadataFlyweight.dataWithoutMarking(byteBuf, hasMetadata); - byteBuf.resetReaderIndex(); - return data; - } - - ByteBuf metadataWithRequestN(ByteBuf byteBuf) { - boolean hasMetadata = FrameHeaderFlyweight.hasMetadata(byteBuf); - if (!hasMetadata) { - return null; - } - byteBuf.markReaderIndex(); - byteBuf.skipBytes(FrameHeaderFlyweight.size() + Integer.BYTES); - ByteBuf metadata = DataAndMetadataFlyweight.metadataWithoutMarking(byteBuf); - byteBuf.resetReaderIndex(); - return metadata; - } - - int initialRequestN(ByteBuf byteBuf) { - byteBuf.markReaderIndex(); - int i = byteBuf.skipBytes(FrameHeaderFlyweight.size()).readInt(); - byteBuf.resetReaderIndex(); - return i; - } -} diff --git a/rsocket-core/src/main/java/io/rsocket/frame/RequestNFrameFlyweight.java b/rsocket-core/src/main/java/io/rsocket/frame/RequestNFrameCodec.java similarity index 68% rename from rsocket-core/src/main/java/io/rsocket/frame/RequestNFrameFlyweight.java rename to rsocket-core/src/main/java/io/rsocket/frame/RequestNFrameCodec.java index fe2c752cf..66bdd46f4 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/RequestNFrameFlyweight.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/RequestNFrameCodec.java @@ -3,8 +3,8 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; -public class RequestNFrameFlyweight { - private RequestNFrameFlyweight() {} +public class RequestNFrameCodec { + private RequestNFrameCodec() {} public static ByteBuf encode( final ByteBufAllocator allocator, final int streamId, long requestN) { @@ -15,14 +15,14 @@ public static ByteBuf encode( int reqN = requestN > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) requestN; - ByteBuf header = FrameHeaderFlyweight.encode(allocator, streamId, FrameType.REQUEST_N, 0); + ByteBuf header = FrameHeaderCodec.encode(allocator, streamId, FrameType.REQUEST_N, 0); return header.writeInt(reqN); } public static long requestN(ByteBuf byteBuf) { - FrameHeaderFlyweight.ensureFrameType(FrameType.REQUEST_N, byteBuf); + FrameHeaderCodec.ensureFrameType(FrameType.REQUEST_N, byteBuf); byteBuf.markReaderIndex(); - byteBuf.skipBytes(FrameHeaderFlyweight.size()); + byteBuf.skipBytes(FrameHeaderCodec.size()); int i = byteBuf.readInt(); byteBuf.resetReaderIndex(); return i == Integer.MAX_VALUE ? Long.MAX_VALUE : i; diff --git a/rsocket-core/src/main/java/io/rsocket/frame/RequestResponseFrameCodec.java b/rsocket-core/src/main/java/io/rsocket/frame/RequestResponseFrameCodec.java new file mode 100644 index 000000000..884a8293b --- /dev/null +++ b/rsocket-core/src/main/java/io/rsocket/frame/RequestResponseFrameCodec.java @@ -0,0 +1,35 @@ +package io.rsocket.frame; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.rsocket.Payload; + +public class RequestResponseFrameCodec { + + private RequestResponseFrameCodec() {} + + public static ByteBuf encodeReleasingPayload( + ByteBufAllocator allocator, int streamId, Payload payload) { + + return GenericFrameCodec.encodeReleasingPayload( + allocator, FrameType.REQUEST_RESPONSE, streamId, false, false, payload); + } + + public static ByteBuf encode( + ByteBufAllocator allocator, + int streamId, + boolean fragmentFollows, + ByteBuf metadata, + ByteBuf data) { + return GenericFrameCodec.encode( + allocator, FrameType.REQUEST_RESPONSE, streamId, fragmentFollows, metadata, data); + } + + public static ByteBuf data(ByteBuf byteBuf) { + return GenericFrameCodec.data(byteBuf); + } + + public static ByteBuf metadata(ByteBuf byteBuf) { + return GenericFrameCodec.metadata(byteBuf); + } +} diff --git a/rsocket-core/src/main/java/io/rsocket/frame/RequestResponseFrameFlyweight.java b/rsocket-core/src/main/java/io/rsocket/frame/RequestResponseFrameFlyweight.java deleted file mode 100644 index 782c70965..000000000 --- a/rsocket-core/src/main/java/io/rsocket/frame/RequestResponseFrameFlyweight.java +++ /dev/null @@ -1,62 +0,0 @@ -package io.rsocket.frame; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.util.IllegalReferenceCountException; -import io.rsocket.Payload; - -public class RequestResponseFrameFlyweight { - private static final RequestFlyweight FLYWEIGHT = - new RequestFlyweight(FrameType.REQUEST_RESPONSE); - - private RequestResponseFrameFlyweight() {} - - public static ByteBuf encodeReleasingPayload( - ByteBufAllocator allocator, int streamId, Payload payload) { - - // if refCnt exceptions throws here it is safe to do no-op - boolean hasMetadata = payload.hasMetadata(); - // if refCnt exceptions throws here it is safe to do no-op still - final ByteBuf metadata = hasMetadata ? payload.metadata().retain() : null; - final ByteBuf data; - // retaining data safely. May throw either NPE or RefCntE - try { - data = payload.data().retain(); - } catch (IllegalReferenceCountException | NullPointerException e) { - if (hasMetadata) { - metadata.release(); - } - throw e; - } - // releasing payload safely since it can be already released wheres we have to release retained - // data and metadata as well - try { - payload.release(); - } catch (IllegalReferenceCountException e) { - data.release(); - if (hasMetadata) { - metadata.release(); - } - throw e; - } - - return encode(allocator, streamId, false, metadata, data); - } - - public static ByteBuf encode( - ByteBufAllocator allocator, - int streamId, - boolean fragmentFollows, - ByteBuf metadata, - ByteBuf data) { - return FLYWEIGHT.encode(allocator, streamId, fragmentFollows, metadata, data); - } - - public static ByteBuf data(ByteBuf byteBuf) { - return FLYWEIGHT.data(byteBuf); - } - - public static ByteBuf metadata(ByteBuf byteBuf) { - return FLYWEIGHT.metadata(byteBuf); - } -} diff --git a/rsocket-core/src/main/java/io/rsocket/frame/RequestStreamFrameCodec.java b/rsocket-core/src/main/java/io/rsocket/frame/RequestStreamFrameCodec.java new file mode 100644 index 000000000..9853a8b54 --- /dev/null +++ b/rsocket-core/src/main/java/io/rsocket/frame/RequestStreamFrameCodec.java @@ -0,0 +1,62 @@ +package io.rsocket.frame; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.rsocket.Payload; + +public class RequestStreamFrameCodec { + + private RequestStreamFrameCodec() {} + + public static ByteBuf encodeReleasingPayload( + ByteBufAllocator allocator, int streamId, long initialRequestN, Payload payload) { + + if (initialRequestN < 1) { + throw new IllegalArgumentException("request n is less than 1"); + } + + int reqN = initialRequestN > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) initialRequestN; + + return GenericFrameCodec.encodeReleasingPayload( + allocator, FrameType.REQUEST_STREAM, streamId, false, false, reqN, payload); + } + + public static ByteBuf encode( + ByteBufAllocator allocator, + int streamId, + boolean fragmentFollows, + long initialRequestN, + ByteBuf metadata, + ByteBuf data) { + + if (initialRequestN < 1) { + throw new IllegalArgumentException("request n is less than 1"); + } + + int reqN = initialRequestN > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) initialRequestN; + + return GenericFrameCodec.encode( + allocator, + FrameType.REQUEST_STREAM, + streamId, + fragmentFollows, + false, + false, + reqN, + metadata, + data); + } + + public static ByteBuf data(ByteBuf byteBuf) { + return GenericFrameCodec.dataWithRequestN(byteBuf); + } + + public static ByteBuf metadata(ByteBuf byteBuf) { + return GenericFrameCodec.metadataWithRequestN(byteBuf); + } + + public static long initialRequestN(ByteBuf byteBuf) { + int requestN = GenericFrameCodec.initialRequestN(byteBuf); + return requestN == Integer.MAX_VALUE ? Long.MAX_VALUE : requestN; + } +} diff --git a/rsocket-core/src/main/java/io/rsocket/frame/RequestStreamFrameFlyweight.java b/rsocket-core/src/main/java/io/rsocket/frame/RequestStreamFrameFlyweight.java deleted file mode 100644 index 2fb209ffb..000000000 --- a/rsocket-core/src/main/java/io/rsocket/frame/RequestStreamFrameFlyweight.java +++ /dev/null @@ -1,76 +0,0 @@ -package io.rsocket.frame; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.util.IllegalReferenceCountException; -import io.rsocket.Payload; - -public class RequestStreamFrameFlyweight { - - private static final RequestFlyweight FLYWEIGHT = new RequestFlyweight(FrameType.REQUEST_STREAM); - - private RequestStreamFrameFlyweight() {} - - public static ByteBuf encodeReleasingPayload( - ByteBufAllocator allocator, int streamId, long initialRequestN, Payload payload) { - - // if refCnt exceptions throws here it is safe to do no-op - boolean hasMetadata = payload.hasMetadata(); - // if refCnt exceptions throws here it is safe to do no-op still - final ByteBuf metadata = hasMetadata ? payload.metadata().retain() : null; - final ByteBuf data; - // retaining data safely. May throw either NPE or RefCntE - try { - data = payload.data().retain(); - } catch (IllegalReferenceCountException | NullPointerException e) { - if (hasMetadata) { - metadata.release(); - } - throw e; - } - // releasing payload safely since it can be already released wheres we have to release retained - // data and metadata as well - try { - payload.release(); - } catch (IllegalReferenceCountException e) { - data.release(); - if (hasMetadata) { - metadata.release(); - } - throw e; - } - - return encode(allocator, streamId, false, initialRequestN, metadata, data); - } - - public static ByteBuf encode( - ByteBufAllocator allocator, - int streamId, - boolean fragmentFollows, - long initialRequestN, - ByteBuf metadata, - ByteBuf data) { - - if (initialRequestN < 1) { - throw new IllegalArgumentException("request n is less than 1"); - } - - int reqN = initialRequestN > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) initialRequestN; - - return FLYWEIGHT.encode( - allocator, streamId, fragmentFollows, false, false, reqN, metadata, data); - } - - public static ByteBuf data(ByteBuf byteBuf) { - return FLYWEIGHT.dataWithRequestN(byteBuf); - } - - public static ByteBuf metadata(ByteBuf byteBuf) { - return FLYWEIGHT.metadataWithRequestN(byteBuf); - } - - public static long initialRequestN(ByteBuf byteBuf) { - int requestN = FLYWEIGHT.initialRequestN(byteBuf); - return requestN == Integer.MAX_VALUE ? Long.MAX_VALUE : requestN; - } -} diff --git a/rsocket-core/src/main/java/io/rsocket/frame/ResumeFrameFlyweight.java b/rsocket-core/src/main/java/io/rsocket/frame/ResumeFrameCodec.java similarity index 79% rename from rsocket-core/src/main/java/io/rsocket/frame/ResumeFrameFlyweight.java rename to rsocket-core/src/main/java/io/rsocket/frame/ResumeFrameCodec.java index 06c9fc38c..aae89f7ab 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/ResumeFrameFlyweight.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/ResumeFrameCodec.java @@ -21,8 +21,8 @@ import io.netty.buffer.Unpooled; import java.util.UUID; -public class ResumeFrameFlyweight { - static final int CURRENT_VERSION = SetupFrameFlyweight.CURRENT_VERSION; +public class ResumeFrameCodec { + static final int CURRENT_VERSION = SetupFrameCodec.CURRENT_VERSION; public static ByteBuf encode( ByteBufAllocator allocator, @@ -30,7 +30,7 @@ public static ByteBuf encode( long lastReceivedServerPos, long firstAvailableClientPos) { - ByteBuf byteBuf = FrameHeaderFlyweight.encodeStreamZero(allocator, FrameType.RESUME, 0); + ByteBuf byteBuf = FrameHeaderCodec.encodeStreamZero(allocator, FrameType.RESUME, 0); byteBuf.writeInt(CURRENT_VERSION); token.markReaderIndex(); byteBuf.writeShort(token.readableBytes()); @@ -43,10 +43,10 @@ public static ByteBuf encode( } public static int version(ByteBuf byteBuf) { - FrameHeaderFlyweight.ensureFrameType(FrameType.RESUME, byteBuf); + FrameHeaderCodec.ensureFrameType(FrameType.RESUME, byteBuf); byteBuf.markReaderIndex(); - byteBuf.skipBytes(FrameHeaderFlyweight.size()); + byteBuf.skipBytes(FrameHeaderCodec.size()); int version = byteBuf.readInt(); byteBuf.resetReaderIndex(); @@ -54,11 +54,11 @@ public static int version(ByteBuf byteBuf) { } public static ByteBuf token(ByteBuf byteBuf) { - FrameHeaderFlyweight.ensureFrameType(FrameType.RESUME, byteBuf); + FrameHeaderCodec.ensureFrameType(FrameType.RESUME, byteBuf); byteBuf.markReaderIndex(); // header + version - int tokenPos = FrameHeaderFlyweight.size() + Integer.BYTES; + int tokenPos = FrameHeaderCodec.size() + Integer.BYTES; byteBuf.skipBytes(tokenPos); // token int tokenLength = byteBuf.readShort() & 0xFFFF; @@ -69,11 +69,11 @@ public static ByteBuf token(ByteBuf byteBuf) { } public static long lastReceivedServerPos(ByteBuf byteBuf) { - FrameHeaderFlyweight.ensureFrameType(FrameType.RESUME, byteBuf); + FrameHeaderCodec.ensureFrameType(FrameType.RESUME, byteBuf); byteBuf.markReaderIndex(); // header + version - int tokenPos = FrameHeaderFlyweight.size() + Integer.BYTES; + int tokenPos = FrameHeaderCodec.size() + Integer.BYTES; byteBuf.skipBytes(tokenPos); // token int tokenLength = byteBuf.readShort() & 0xFFFF; @@ -85,11 +85,11 @@ public static long lastReceivedServerPos(ByteBuf byteBuf) { } public static long firstAvailableClientPos(ByteBuf byteBuf) { - FrameHeaderFlyweight.ensureFrameType(FrameType.RESUME, byteBuf); + FrameHeaderCodec.ensureFrameType(FrameType.RESUME, byteBuf); byteBuf.markReaderIndex(); // header + version - int tokenPos = FrameHeaderFlyweight.size() + Integer.BYTES; + int tokenPos = FrameHeaderCodec.size() + Integer.BYTES; byteBuf.skipBytes(tokenPos); // token int tokenLength = byteBuf.readShort() & 0xFFFF; diff --git a/rsocket-core/src/main/java/io/rsocket/frame/ResumeOkFrameFlyweight.java b/rsocket-core/src/main/java/io/rsocket/frame/ResumeOkFrameCodec.java similarity index 67% rename from rsocket-core/src/main/java/io/rsocket/frame/ResumeOkFrameFlyweight.java rename to rsocket-core/src/main/java/io/rsocket/frame/ResumeOkFrameCodec.java index dd1971603..2b6951e49 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/ResumeOkFrameFlyweight.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/ResumeOkFrameCodec.java @@ -3,18 +3,18 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; -public class ResumeOkFrameFlyweight { +public class ResumeOkFrameCodec { public static ByteBuf encode(final ByteBufAllocator allocator, long lastReceivedClientPos) { - ByteBuf byteBuf = FrameHeaderFlyweight.encodeStreamZero(allocator, FrameType.RESUME_OK, 0); + ByteBuf byteBuf = FrameHeaderCodec.encodeStreamZero(allocator, FrameType.RESUME_OK, 0); byteBuf.writeLong(lastReceivedClientPos); return byteBuf; } public static long lastReceivedClientPos(ByteBuf byteBuf) { - FrameHeaderFlyweight.ensureFrameType(FrameType.RESUME_OK, byteBuf); + FrameHeaderCodec.ensureFrameType(FrameType.RESUME_OK, byteBuf); byteBuf.markReaderIndex(); - long lastReceivedClientPosition = byteBuf.skipBytes(FrameHeaderFlyweight.size()).readLong(); + long lastReceivedClientPosition = byteBuf.skipBytes(FrameHeaderCodec.size()).readLong(); byteBuf.resetReaderIndex(); return lastReceivedClientPosition; diff --git a/rsocket-core/src/main/java/io/rsocket/frame/SetupFrameFlyweight.java b/rsocket-core/src/main/java/io/rsocket/frame/SetupFrameCodec.java similarity index 83% rename from rsocket-core/src/main/java/io/rsocket/frame/SetupFrameFlyweight.java rename to rsocket-core/src/main/java/io/rsocket/frame/SetupFrameCodec.java index bfb73fe22..d6f7431e4 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/SetupFrameFlyweight.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/SetupFrameCodec.java @@ -7,7 +7,7 @@ import io.rsocket.Payload; import java.nio.charset.StandardCharsets; -public class SetupFrameFlyweight { +public class SetupFrameCodec { /** * A flag used to indicate that the client requires connection resumption, if possible (the frame * contains a Resume Identification Token) @@ -17,9 +17,9 @@ public class SetupFrameFlyweight { /** A flag used to indicate that the client will honor LEASE sent by the server */ public static final int FLAGS_WILL_HONOR_LEASE = 0b00_0100_0000; - public static final int CURRENT_VERSION = VersionFlyweight.encode(1, 0); + public static final int CURRENT_VERSION = VersionCodec.encode(1, 0); - private static final int VERSION_FIELD_OFFSET = FrameHeaderFlyweight.size(); + private static final int VERSION_FIELD_OFFSET = FrameHeaderCodec.size(); private static final int KEEPALIVE_INTERVAL_FIELD_OFFSET = VERSION_FIELD_OFFSET + Integer.BYTES; private static final int KEEPALIVE_MAX_LIFETIME_FIELD_OFFSET = KEEPALIVE_INTERVAL_FIELD_OFFSET + Integer.BYTES; @@ -70,10 +70,10 @@ public static ByteBuf encode( } if (hasMetadata) { - flags |= FrameHeaderFlyweight.FLAGS_M; + flags |= FrameHeaderCodec.FLAGS_M; } - final ByteBuf header = FrameHeaderFlyweight.encodeStreamZero(allocator, FrameType.SETUP, flags); + final ByteBuf header = FrameHeaderCodec.encodeStreamZero(allocator, FrameType.SETUP, flags); header.writeInt(CURRENT_VERSION).writeInt(keepaliveInterval).writeInt(maxLifetime); @@ -93,11 +93,11 @@ public static ByteBuf encode( header.writeByte(length); ByteBufUtil.writeUtf8(header, dataMimeType); - return DataAndMetadataFlyweight.encode(allocator, header, metadata, hasMetadata, data); + return FrameBodyCodec.encode(allocator, header, metadata, hasMetadata, data); } public static int version(ByteBuf byteBuf) { - FrameHeaderFlyweight.ensureFrameType(FrameType.SETUP, byteBuf); + FrameHeaderCodec.ensureFrameType(FrameType.SETUP, byteBuf); byteBuf.markReaderIndex(); int version = byteBuf.skipBytes(VERSION_FIELD_OFFSET).readInt(); byteBuf.resetReaderIndex(); @@ -106,7 +106,7 @@ public static int version(ByteBuf byteBuf) { public static String humanReadableVersion(ByteBuf byteBuf) { int encodedVersion = version(byteBuf); - return VersionFlyweight.major(encodedVersion) + "." + VersionFlyweight.minor(encodedVersion); + return VersionCodec.major(encodedVersion) + "." + VersionCodec.minor(encodedVersion); } public static boolean isSupportedVersion(ByteBuf byteBuf) { @@ -135,11 +135,11 @@ public static int keepAliveMaxLifetime(ByteBuf byteBuf) { } public static boolean honorLease(ByteBuf byteBuf) { - return (FLAGS_WILL_HONOR_LEASE & FrameHeaderFlyweight.flags(byteBuf)) == FLAGS_WILL_HONOR_LEASE; + return (FLAGS_WILL_HONOR_LEASE & FrameHeaderCodec.flags(byteBuf)) == FLAGS_WILL_HONOR_LEASE; } public static boolean resumeEnabled(ByteBuf byteBuf) { - return (FLAGS_RESUME_ENABLE & FrameHeaderFlyweight.flags(byteBuf)) == FLAGS_RESUME_ENABLE; + return (FLAGS_RESUME_ENABLE & FrameHeaderCodec.flags(byteBuf)) == FLAGS_RESUME_ENABLE; } public static ByteBuf resumeToken(ByteBuf byteBuf) { @@ -147,7 +147,7 @@ public static ByteBuf resumeToken(ByteBuf byteBuf) { byteBuf.markReaderIndex(); // header int resumePos = - FrameHeaderFlyweight.size() + FrameHeaderCodec.size() + // version Integer.BYTES @@ -187,29 +187,29 @@ public static String dataMimeType(ByteBuf byteBuf) { } public static ByteBuf metadata(ByteBuf byteBuf) { - boolean hasMetadata = FrameHeaderFlyweight.hasMetadata(byteBuf); + boolean hasMetadata = FrameHeaderCodec.hasMetadata(byteBuf); if (!hasMetadata) { return null; } byteBuf.markReaderIndex(); skipToPayload(byteBuf); - ByteBuf metadata = DataAndMetadataFlyweight.metadataWithoutMarking(byteBuf); + ByteBuf metadata = FrameBodyCodec.metadataWithoutMarking(byteBuf); byteBuf.resetReaderIndex(); return metadata; } public static ByteBuf data(ByteBuf byteBuf) { - boolean hasMetadata = FrameHeaderFlyweight.hasMetadata(byteBuf); + boolean hasMetadata = FrameHeaderCodec.hasMetadata(byteBuf); byteBuf.markReaderIndex(); skipToPayload(byteBuf); - ByteBuf data = DataAndMetadataFlyweight.dataWithoutMarking(byteBuf, hasMetadata); + ByteBuf data = FrameBodyCodec.dataWithoutMarking(byteBuf, hasMetadata); byteBuf.resetReaderIndex(); return data; } private static int bytesToSkipToMimeType(ByteBuf byteBuf) { int bytesToSkip = VARIABLE_DATA_OFFSET; - if ((FLAGS_RESUME_ENABLE & FrameHeaderFlyweight.flags(byteBuf)) == FLAGS_RESUME_ENABLE) { + if ((FLAGS_RESUME_ENABLE & FrameHeaderCodec.flags(byteBuf)) == FLAGS_RESUME_ENABLE) { bytesToSkip += resumeTokenLength(byteBuf) + Short.BYTES; } return bytesToSkip; diff --git a/rsocket-core/src/main/java/io/rsocket/frame/VersionFlyweight.java b/rsocket-core/src/main/java/io/rsocket/frame/VersionCodec.java similarity index 96% rename from rsocket-core/src/main/java/io/rsocket/frame/VersionFlyweight.java rename to rsocket-core/src/main/java/io/rsocket/frame/VersionCodec.java index e238b3fe2..35e4aa86a 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/VersionFlyweight.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/VersionCodec.java @@ -16,7 +16,7 @@ package io.rsocket.frame; -public class VersionFlyweight { +public class VersionCodec { public static int encode(int major, int minor) { return (major << 16) | (minor & 0xFFFF); diff --git a/rsocket-core/src/main/java/io/rsocket/frame/decoder/DefaultPayloadDecoder.java b/rsocket-core/src/main/java/io/rsocket/frame/decoder/DefaultPayloadDecoder.java index 0a77e3820..e6874c097 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/decoder/DefaultPayloadDecoder.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/decoder/DefaultPayloadDecoder.java @@ -3,14 +3,14 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.rsocket.Payload; -import io.rsocket.frame.FrameHeaderFlyweight; +import io.rsocket.frame.FrameHeaderCodec; import io.rsocket.frame.FrameType; -import io.rsocket.frame.MetadataPushFrameFlyweight; -import io.rsocket.frame.PayloadFrameFlyweight; -import io.rsocket.frame.RequestChannelFrameFlyweight; -import io.rsocket.frame.RequestFireAndForgetFrameFlyweight; -import io.rsocket.frame.RequestResponseFrameFlyweight; -import io.rsocket.frame.RequestStreamFrameFlyweight; +import io.rsocket.frame.MetadataPushFrameCodec; +import io.rsocket.frame.PayloadFrameCodec; +import io.rsocket.frame.RequestChannelFrameCodec; +import io.rsocket.frame.RequestFireAndForgetFrameCodec; +import io.rsocket.frame.RequestResponseFrameCodec; +import io.rsocket.frame.RequestStreamFrameCodec; import io.rsocket.util.DefaultPayload; import java.nio.ByteBuffer; @@ -21,32 +21,32 @@ class DefaultPayloadDecoder implements PayloadDecoder { public Payload apply(ByteBuf byteBuf) { ByteBuf m; ByteBuf d; - FrameType type = FrameHeaderFlyweight.frameType(byteBuf); + FrameType type = FrameHeaderCodec.frameType(byteBuf); switch (type) { case REQUEST_FNF: - d = RequestFireAndForgetFrameFlyweight.data(byteBuf); - m = RequestFireAndForgetFrameFlyweight.metadata(byteBuf); + d = RequestFireAndForgetFrameCodec.data(byteBuf); + m = RequestFireAndForgetFrameCodec.metadata(byteBuf); break; case REQUEST_RESPONSE: - d = RequestResponseFrameFlyweight.data(byteBuf); - m = RequestResponseFrameFlyweight.metadata(byteBuf); + d = RequestResponseFrameCodec.data(byteBuf); + m = RequestResponseFrameCodec.metadata(byteBuf); break; case REQUEST_STREAM: - d = RequestStreamFrameFlyweight.data(byteBuf); - m = RequestStreamFrameFlyweight.metadata(byteBuf); + d = RequestStreamFrameCodec.data(byteBuf); + m = RequestStreamFrameCodec.metadata(byteBuf); break; case REQUEST_CHANNEL: - d = RequestChannelFrameFlyweight.data(byteBuf); - m = RequestChannelFrameFlyweight.metadata(byteBuf); + d = RequestChannelFrameCodec.data(byteBuf); + m = RequestChannelFrameCodec.metadata(byteBuf); break; case NEXT: case NEXT_COMPLETE: - d = PayloadFrameFlyweight.data(byteBuf); - m = PayloadFrameFlyweight.metadata(byteBuf); + d = PayloadFrameCodec.data(byteBuf); + m = PayloadFrameCodec.metadata(byteBuf); break; case METADATA_PUSH: d = Unpooled.EMPTY_BUFFER; - m = MetadataPushFrameFlyweight.metadata(byteBuf); + m = MetadataPushFrameCodec.metadata(byteBuf); break; default: throw new IllegalArgumentException("unsupported frame type: " + type); diff --git a/rsocket-core/src/main/java/io/rsocket/frame/decoder/ZeroCopyPayloadDecoder.java b/rsocket-core/src/main/java/io/rsocket/frame/decoder/ZeroCopyPayloadDecoder.java index c92f82428..3a0dc7bb5 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/decoder/ZeroCopyPayloadDecoder.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/decoder/ZeroCopyPayloadDecoder.java @@ -3,14 +3,14 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.rsocket.Payload; -import io.rsocket.frame.FrameHeaderFlyweight; +import io.rsocket.frame.FrameHeaderCodec; import io.rsocket.frame.FrameType; -import io.rsocket.frame.MetadataPushFrameFlyweight; -import io.rsocket.frame.PayloadFrameFlyweight; -import io.rsocket.frame.RequestChannelFrameFlyweight; -import io.rsocket.frame.RequestFireAndForgetFrameFlyweight; -import io.rsocket.frame.RequestResponseFrameFlyweight; -import io.rsocket.frame.RequestStreamFrameFlyweight; +import io.rsocket.frame.MetadataPushFrameCodec; +import io.rsocket.frame.PayloadFrameCodec; +import io.rsocket.frame.RequestChannelFrameCodec; +import io.rsocket.frame.RequestFireAndForgetFrameCodec; +import io.rsocket.frame.RequestResponseFrameCodec; +import io.rsocket.frame.RequestStreamFrameCodec; import io.rsocket.util.ByteBufPayload; /** @@ -22,32 +22,32 @@ public class ZeroCopyPayloadDecoder implements PayloadDecoder { public Payload apply(ByteBuf byteBuf) { ByteBuf m; ByteBuf d; - FrameType type = FrameHeaderFlyweight.frameType(byteBuf); + FrameType type = FrameHeaderCodec.frameType(byteBuf); switch (type) { case REQUEST_FNF: - d = RequestFireAndForgetFrameFlyweight.data(byteBuf); - m = RequestFireAndForgetFrameFlyweight.metadata(byteBuf); + d = RequestFireAndForgetFrameCodec.data(byteBuf); + m = RequestFireAndForgetFrameCodec.metadata(byteBuf); break; case REQUEST_RESPONSE: - d = RequestResponseFrameFlyweight.data(byteBuf); - m = RequestResponseFrameFlyweight.metadata(byteBuf); + d = RequestResponseFrameCodec.data(byteBuf); + m = RequestResponseFrameCodec.metadata(byteBuf); break; case REQUEST_STREAM: - d = RequestStreamFrameFlyweight.data(byteBuf); - m = RequestStreamFrameFlyweight.metadata(byteBuf); + d = RequestStreamFrameCodec.data(byteBuf); + m = RequestStreamFrameCodec.metadata(byteBuf); break; case REQUEST_CHANNEL: - d = RequestChannelFrameFlyweight.data(byteBuf); - m = RequestChannelFrameFlyweight.metadata(byteBuf); + d = RequestChannelFrameCodec.data(byteBuf); + m = RequestChannelFrameCodec.metadata(byteBuf); break; case NEXT: case NEXT_COMPLETE: - d = PayloadFrameFlyweight.data(byteBuf); - m = PayloadFrameFlyweight.metadata(byteBuf); + d = PayloadFrameCodec.data(byteBuf); + m = PayloadFrameCodec.metadata(byteBuf); break; case METADATA_PUSH: d = Unpooled.EMPTY_BUFFER; - m = MetadataPushFrameFlyweight.metadata(byteBuf); + m = MetadataPushFrameCodec.metadata(byteBuf); break; default: throw new IllegalArgumentException("unsupported frame type: " + type); diff --git a/rsocket-core/src/main/java/io/rsocket/internal/ClientServerInputMultiplexer.java b/rsocket-core/src/main/java/io/rsocket/internal/ClientServerInputMultiplexer.java index cf3eeb120..c294d6539 100644 --- a/rsocket-core/src/main/java/io/rsocket/internal/ClientServerInputMultiplexer.java +++ b/rsocket-core/src/main/java/io/rsocket/internal/ClientServerInputMultiplexer.java @@ -20,7 +20,7 @@ import io.netty.buffer.ByteBufAllocator; import io.rsocket.Closeable; import io.rsocket.DuplexConnection; -import io.rsocket.frame.FrameHeaderFlyweight; +import io.rsocket.frame.FrameHeaderCodec; import io.rsocket.frame.FrameUtil; import io.rsocket.plugins.DuplexConnectionInterceptor.Type; import io.rsocket.plugins.InitializingInterceptorRegistry; @@ -79,10 +79,10 @@ public ClientServerInputMultiplexer( .receive() .groupBy( frame -> { - int streamId = FrameHeaderFlyweight.streamId(frame); + int streamId = FrameHeaderCodec.streamId(frame); final Type type; if (streamId == 0) { - switch (FrameHeaderFlyweight.frameType(frame)) { + switch (FrameHeaderCodec.frameType(frame)) { case SETUP: case RESUME: case RESUME_OK: diff --git a/rsocket-core/src/main/java/io/rsocket/keepalive/KeepAliveSupport.java b/rsocket-core/src/main/java/io/rsocket/keepalive/KeepAliveSupport.java index ea8a0de22..db29d8030 100644 --- a/rsocket-core/src/main/java/io/rsocket/keepalive/KeepAliveSupport.java +++ b/rsocket-core/src/main/java/io/rsocket/keepalive/KeepAliveSupport.java @@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.Unpooled; -import io.rsocket.frame.KeepAliveFrameFlyweight; +import io.rsocket.frame.KeepAliveFrameCodec; import io.rsocket.resume.ResumeStateHolder; import java.time.Duration; import java.util.concurrent.atomic.AtomicBoolean; @@ -69,14 +69,14 @@ public void receive(ByteBuf keepAliveFrame) { long remoteLastReceivedPos = remoteLastReceivedPosition(keepAliveFrame); resumeStateHolder.onImpliedPosition(remoteLastReceivedPos); } - if (KeepAliveFrameFlyweight.respondFlag(keepAliveFrame)) { + if (KeepAliveFrameCodec.respondFlag(keepAliveFrame)) { long localLastReceivedPos = localLastReceivedPosition(); send( - KeepAliveFrameFlyweight.encode( + KeepAliveFrameCodec.encode( allocator, false, localLastReceivedPos, - KeepAliveFrameFlyweight.data(keepAliveFrame).retain())); + KeepAliveFrameCodec.data(keepAliveFrame).retain())); } } @@ -118,7 +118,7 @@ long localLastReceivedPosition() { } long remoteLastReceivedPosition(ByteBuf keepAliveFrame) { - return KeepAliveFrameFlyweight.lastPosition(keepAliveFrame); + return KeepAliveFrameCodec.lastPosition(keepAliveFrame); } public static final class ServerKeepAliveSupport extends KeepAliveSupport { @@ -145,7 +145,7 @@ public ClientKeepAliveSupport( void onIntervalTick() { tryTimeout(); send( - KeepAliveFrameFlyweight.encode( + KeepAliveFrameCodec.encode( allocator, true, localLastReceivedPosition(), Unpooled.EMPTY_BUFFER)); } } diff --git a/rsocket-core/src/main/java/io/rsocket/lease/RequesterLeaseHandler.java b/rsocket-core/src/main/java/io/rsocket/lease/RequesterLeaseHandler.java index dd4247090..fd569a2c8 100644 --- a/rsocket-core/src/main/java/io/rsocket/lease/RequesterLeaseHandler.java +++ b/rsocket-core/src/main/java/io/rsocket/lease/RequesterLeaseHandler.java @@ -18,7 +18,7 @@ import io.netty.buffer.ByteBuf; import io.rsocket.Availability; -import io.rsocket.frame.LeaseFrameFlyweight; +import io.rsocket.frame.LeaseFrameCodec; import java.util.function.Consumer; import reactor.core.Disposable; import reactor.core.publisher.Flux; @@ -63,9 +63,9 @@ public Exception leaseError() { @Override public void receive(ByteBuf leaseFrame) { - int numberOfRequests = LeaseFrameFlyweight.numRequests(leaseFrame); - int timeToLiveMillis = LeaseFrameFlyweight.ttl(leaseFrame); - ByteBuf metadata = LeaseFrameFlyweight.metadata(leaseFrame); + int numberOfRequests = LeaseFrameCodec.numRequests(leaseFrame); + int timeToLiveMillis = LeaseFrameCodec.ttl(leaseFrame); + ByteBuf metadata = LeaseFrameCodec.metadata(leaseFrame); LeaseImpl lease = LeaseImpl.create(timeToLiveMillis, numberOfRequests, metadata); currentLease = lease; receivedLease.onNext(lease); diff --git a/rsocket-core/src/main/java/io/rsocket/lease/ResponderLeaseHandler.java b/rsocket-core/src/main/java/io/rsocket/lease/ResponderLeaseHandler.java index 5ca745ee7..5f000cb30 100644 --- a/rsocket-core/src/main/java/io/rsocket/lease/ResponderLeaseHandler.java +++ b/rsocket-core/src/main/java/io/rsocket/lease/ResponderLeaseHandler.java @@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.rsocket.Availability; -import io.rsocket.frame.LeaseFrameFlyweight; +import io.rsocket.frame.LeaseFrameCodec; import java.util.Optional; import java.util.function.Consumer; import java.util.function.Function; @@ -96,7 +96,7 @@ public double availability() { } private ByteBuf createLeaseFrame(Lease lease) { - return LeaseFrameFlyweight.encode( + return LeaseFrameCodec.encode( allocator, lease.getTimeToLiveMillis(), lease.getAllowedRequests(), lease.getMetadata()); } diff --git a/rsocket-core/src/main/java/io/rsocket/metadata/AuthMetadataCodec.java b/rsocket-core/src/main/java/io/rsocket/metadata/AuthMetadataCodec.java new file mode 100644 index 000000000..41dafb33d --- /dev/null +++ b/rsocket-core/src/main/java/io/rsocket/metadata/AuthMetadataCodec.java @@ -0,0 +1,335 @@ +package io.rsocket.metadata; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; +import io.netty.util.CharsetUtil; +import io.rsocket.util.CharByteBufUtil; + +public class AuthMetadataCodec { + + static final int STREAM_METADATA_KNOWN_MASK = 0x80; // 1000 0000 + static final byte STREAM_METADATA_LENGTH_MASK = 0x7F; // 0111 1111 + + static final int USERNAME_BYTES_LENGTH = 1; + static final int AUTH_TYPE_ID_LENGTH = 1; + + static final char[] EMPTY_CHARS_ARRAY = new char[0]; + + private AuthMetadataCodec() {} + + /** + * Encode a Authentication CompositeMetadata payload using custom authentication type + * + * @param allocator the {@link ByteBufAllocator} to use to create intermediate buffers as needed. + * @param customAuthType the custom mime type to encode. + * @param metadata the metadata value to encode. + * @throws IllegalArgumentException in case of {@code customAuthType} is non US_ASCII string or + * empty string or its length is greater than 128 bytes + */ + public static ByteBuf encodeMetadata( + ByteBufAllocator allocator, String customAuthType, ByteBuf metadata) { + + int actualASCIILength = ByteBufUtil.utf8Bytes(customAuthType); + if (actualASCIILength != customAuthType.length()) { + throw new IllegalArgumentException("custom auth type must be US_ASCII characters only"); + } + if (actualASCIILength < 1 || actualASCIILength > 128) { + throw new IllegalArgumentException( + "custom auth type must have a strictly positive length that fits on 7 unsigned bits, ie 1-128"); + } + + int capacity = 1 + actualASCIILength; + ByteBuf headerBuffer = allocator.buffer(capacity, capacity); + // encoded length is one less than actual length, since 0 is never a valid length, which gives + // wider representation range + headerBuffer.writeByte(actualASCIILength - 1); + + ByteBufUtil.reserveAndWriteUtf8(headerBuffer, customAuthType, actualASCIILength); + + return allocator.compositeBuffer(2).addComponents(true, headerBuffer, metadata); + } + + /** + * Encode a Authentication CompositeMetadata payload using custom authentication type + * + * @param allocator the {@link ByteBufAllocator} to create intermediate buffers as needed. + * @param authType the well-known mime type to encode. + * @param metadata the metadata value to encode. + * @throws IllegalArgumentException in case of {@code authType} is {@link + * WellKnownAuthType#UNPARSEABLE_AUTH_TYPE} or {@link + * WellKnownAuthType#UNKNOWN_RESERVED_AUTH_TYPE} + */ + public static ByteBuf encodeMetadata( + ByteBufAllocator allocator, WellKnownAuthType authType, ByteBuf metadata) { + + if (authType == WellKnownAuthType.UNPARSEABLE_AUTH_TYPE + || authType == WellKnownAuthType.UNKNOWN_RESERVED_AUTH_TYPE) { + throw new IllegalArgumentException("only allowed AuthType should be used"); + } + + int capacity = AUTH_TYPE_ID_LENGTH; + ByteBuf headerBuffer = + allocator + .buffer(capacity, capacity) + .writeByte(authType.getIdentifier() | STREAM_METADATA_KNOWN_MASK); + + return allocator.compositeBuffer(2).addComponents(true, headerBuffer, metadata); + } + + /** + * Encode a Authentication CompositeMetadata payload using Simple Authentication format + * + * @throws IllegalArgumentException if the username length is greater than 255 + * @param allocator the {@link ByteBufAllocator} to use to create intermediate buffers as needed. + * @param username the char sequence which represents user name. + * @param password the char sequence which represents user password. + */ + public static ByteBuf encodeSimpleMetadata( + ByteBufAllocator allocator, char[] username, char[] password) { + + int usernameLength = CharByteBufUtil.utf8Bytes(username); + if (usernameLength > 255) { + throw new IllegalArgumentException( + "Username should be shorter than or equal to 255 bytes length in UTF-8 encoding"); + } + + int passwordLength = CharByteBufUtil.utf8Bytes(password); + int capacity = AUTH_TYPE_ID_LENGTH + USERNAME_BYTES_LENGTH + usernameLength + passwordLength; + final ByteBuf buffer = + allocator + .buffer(capacity, capacity) + .writeByte(WellKnownAuthType.SIMPLE.getIdentifier() | STREAM_METADATA_KNOWN_MASK) + .writeByte(usernameLength); + + CharByteBufUtil.writeUtf8(buffer, username); + CharByteBufUtil.writeUtf8(buffer, password); + + return buffer; + } + + /** + * Encode a Authentication CompositeMetadata payload using Bearer Authentication format + * + * @param allocator the {@link ByteBufAllocator} to use to create intermediate buffers as needed. + * @param token the char sequence which represents BEARER token. + */ + public static ByteBuf encodeBearerMetadata(ByteBufAllocator allocator, char[] token) { + + int tokenLength = CharByteBufUtil.utf8Bytes(token); + int capacity = AUTH_TYPE_ID_LENGTH + tokenLength; + final ByteBuf buffer = + allocator + .buffer(capacity, capacity) + .writeByte(WellKnownAuthType.BEARER.getIdentifier() | STREAM_METADATA_KNOWN_MASK); + + CharByteBufUtil.writeUtf8(buffer, token); + + return buffer; + } + + /** + * Encode a new Authentication Metadata payload information, first verifying if the passed {@link + * String} matches a {@link WellKnownAuthType} (in which case it will be encoded in a compressed + * fashion using the mime id of that type). + * + *

Prefer using {@link #encodeMetadata(ByteBufAllocator, String, ByteBuf)} if you already know + * that the mime type is not a {@link WellKnownAuthType}. + * + * @param allocator the {@link ByteBufAllocator} to use to create intermediate buffers as needed. + * @param authType the mime type to encode, as a {@link String}. well known mime types are + * compressed. + * @param metadata the metadata value to encode. + * @see #encodeMetadata(ByteBufAllocator, WellKnownAuthType, ByteBuf) + * @see #encodeMetadata(ByteBufAllocator, String, ByteBuf) + */ + public static ByteBuf encodeMetadataWithCompression( + ByteBufAllocator allocator, String authType, ByteBuf metadata) { + WellKnownAuthType wkn = WellKnownAuthType.fromString(authType); + if (wkn == WellKnownAuthType.UNPARSEABLE_AUTH_TYPE) { + return AuthMetadataCodec.encodeMetadata(allocator, authType, metadata); + } else { + return AuthMetadataCodec.encodeMetadata(allocator, wkn, metadata); + } + } + + /** + * Get the first {@code byte} from a {@link ByteBuf} and check whether it is length or {@link + * WellKnownAuthType}. Assuming said buffer properly contains such a {@code byte} + * + * @param metadata byteBuf used to get information from + */ + public static boolean isWellKnownAuthType(ByteBuf metadata) { + byte lengthOrId = metadata.getByte(0); + return (lengthOrId & STREAM_METADATA_LENGTH_MASK) != lengthOrId; + } + + /** + * Read first byte from the given {@code metadata} and tries to convert it's value to {@link + * WellKnownAuthType}. + * + * @param metadata given metadata buffer to read from + * @return Return on of the know Auth types or {@link WellKnownAuthType#UNPARSEABLE_AUTH_TYPE} if + * field's value is length or unknown auth type + * @throws IllegalStateException if not enough readable bytes in the given {@link ByteBuf} + */ + public static WellKnownAuthType decodeWellKnownAuthType(ByteBuf metadata) { + if (metadata.readableBytes() < 1) { + throw new IllegalStateException( + "Unable to decode Well Know Auth type. Not enough readable bytes"); + } + byte lengthOrId = metadata.readByte(); + int normalizedId = (byte) (lengthOrId & STREAM_METADATA_LENGTH_MASK); + + if (normalizedId != lengthOrId) { + return WellKnownAuthType.fromIdentifier(normalizedId); + } + + return WellKnownAuthType.UNPARSEABLE_AUTH_TYPE; + } + + /** + * Read up to 129 bytes from the given metadata in order to get the custom Auth Type + * + * @param metadata + * @return + */ + public static CharSequence decodeCustomAuthType(ByteBuf metadata) { + if (metadata.readableBytes() < 2) { + throw new IllegalStateException( + "Unable to decode custom Auth type. Not enough readable bytes"); + } + + byte encodedLength = metadata.readByte(); + if (encodedLength < 0) { + throw new IllegalStateException( + "Unable to decode custom Auth type. Incorrect auth type length"); + } + + // encoded length is realLength - 1 in order to avoid intersection with 0x00 authtype + int realLength = encodedLength + 1; + if (metadata.readableBytes() < realLength) { + throw new IllegalArgumentException( + "Unable to decode custom Auth type. Malformed length or auth type string"); + } + + return metadata.readCharSequence(realLength, CharsetUtil.US_ASCII); + } + + /** + * Read all remaining {@code bytes} from the given {@link ByteBuf} and return sliced + * representation of a payload + * + * @param metadata metadata to get payload from. Please note, the {@code metadata#readIndex} + * should be set to the beginning of the payload bytes + * @return sliced {@link ByteBuf} or {@link Unpooled#EMPTY_BUFFER} if no bytes readable in the + * given one + */ + public static ByteBuf decodePayload(ByteBuf metadata) { + if (metadata.readableBytes() == 0) { + return Unpooled.EMPTY_BUFFER; + } + + return metadata.readSlice(metadata.readableBytes()); + } + + /** + * Read up to 257 {@code bytes} from the given {@link ByteBuf} where the first byte is username + * length and the subsequent number of bytes equal to decoded length + * + * @param simpleAuthMetadata the given metadata to read username from. Please note, the {@code + * simpleAuthMetadata#readIndex} should be set to the username length byte + * @return sliced {@link ByteBuf} or {@link Unpooled#EMPTY_BUFFER} if username length is zero + */ + public static ByteBuf decodeUsername(ByteBuf simpleAuthMetadata) { + short usernameLength = decodeUsernameLength(simpleAuthMetadata); + + if (usernameLength == 0) { + return Unpooled.EMPTY_BUFFER; + } + + return simpleAuthMetadata.readSlice(usernameLength); + } + + /** + * Read all the remaining {@code byte}s from the given {@link ByteBuf} which represents user's + * password + * + * @param simpleAuthMetadata the given metadata to read password from. Please note, the {@code + * simpleAuthMetadata#readIndex} should be set to the beginning of the password bytes + * @return sliced {@link ByteBuf} or {@link Unpooled#EMPTY_BUFFER} if password length is zero + */ + public static ByteBuf decodePassword(ByteBuf simpleAuthMetadata) { + if (simpleAuthMetadata.readableBytes() == 0) { + return Unpooled.EMPTY_BUFFER; + } + + return simpleAuthMetadata.readSlice(simpleAuthMetadata.readableBytes()); + } + /** + * Read up to 257 {@code bytes} from the given {@link ByteBuf} where the first byte is username + * length and the subsequent number of bytes equal to decoded length + * + * @param simpleAuthMetadata the given metadata to read username from. Please note, the {@code + * simpleAuthMetadata#readIndex} should be set to the username length byte + * @return {@code char[]} which represents UTF-8 username + */ + public static char[] decodeUsernameAsCharArray(ByteBuf simpleAuthMetadata) { + short usernameLength = decodeUsernameLength(simpleAuthMetadata); + + if (usernameLength == 0) { + return EMPTY_CHARS_ARRAY; + } + + return CharByteBufUtil.readUtf8(simpleAuthMetadata, usernameLength); + } + + /** + * Read all the remaining {@code byte}s from the given {@link ByteBuf} which represents user's + * password + * + * @param simpleAuthMetadata the given metadata to read username from. Please note, the {@code + * simpleAuthMetadata#readIndex} should be set to the beginning of the password bytes + * @return {@code char[]} which represents UTF-8 password + */ + public static char[] decodePasswordAsCharArray(ByteBuf simpleAuthMetadata) { + if (simpleAuthMetadata.readableBytes() == 0) { + return EMPTY_CHARS_ARRAY; + } + + return CharByteBufUtil.readUtf8(simpleAuthMetadata, simpleAuthMetadata.readableBytes()); + } + + /** + * Read all the remaining {@code bytes} from the given {@link ByteBuf} where the first byte is + * username length and the subsequent number of bytes equal to decoded length + * + * @param bearerAuthMetadata the given metadata to read username from. Please note, the {@code + * simpleAuthMetadata#readIndex} should be set to the beginning of the password bytes + * @return {@code char[]} which represents UTF-8 password + */ + public static char[] decodeBearerTokenAsCharArray(ByteBuf bearerAuthMetadata) { + if (bearerAuthMetadata.readableBytes() == 0) { + return EMPTY_CHARS_ARRAY; + } + + return CharByteBufUtil.readUtf8(bearerAuthMetadata, bearerAuthMetadata.readableBytes()); + } + + private static short decodeUsernameLength(ByteBuf simpleAuthMetadata) { + if (simpleAuthMetadata.readableBytes() < 1) { + throw new IllegalStateException( + "Unable to decode custom username. Not enough readable bytes"); + } + + short usernameLength = simpleAuthMetadata.readUnsignedByte(); + + if (simpleAuthMetadata.readableBytes() < usernameLength) { + throw new IllegalArgumentException( + "Unable to decode username. Malformed username length or content"); + } + + return usernameLength; + } +} diff --git a/rsocket-core/src/main/java/io/rsocket/metadata/CompositeMetadataCodec.java b/rsocket-core/src/main/java/io/rsocket/metadata/CompositeMetadataCodec.java new file mode 100644 index 000000000..5e00abba8 --- /dev/null +++ b/rsocket-core/src/main/java/io/rsocket/metadata/CompositeMetadataCodec.java @@ -0,0 +1,385 @@ +/* + * Copyright 2015-2018 the original author or authors. + * + * Licensed 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 io.rsocket.metadata; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.CompositeByteBuf; +import io.netty.util.CharsetUtil; +import io.rsocket.util.NumberUtils; +import reactor.util.annotation.Nullable; + +/** + * A flyweight class that can be used to encode/decode composite metadata information to/from {@link + * ByteBuf}. This is intended for low-level efficient manipulation of such buffers. See {@link + * CompositeMetadata} for an Iterator-like approach to decoding entries. + */ +public class CompositeMetadataCodec { + + static final int STREAM_METADATA_KNOWN_MASK = 0x80; // 1000 0000 + + static final byte STREAM_METADATA_LENGTH_MASK = 0x7F; // 0111 1111 + + private CompositeMetadataCodec() {} + + public static int computeNextEntryIndex( + int currentEntryIndex, ByteBuf headerSlice, ByteBuf contentSlice) { + return currentEntryIndex + + headerSlice.readableBytes() // this includes the mime length byte + + 3 // 3 bytes of the content length, which are excluded from the slice + + contentSlice.readableBytes(); + } + + /** + * Decode the next metadata entry (a mime header + content pair of {@link ByteBuf}) from a {@link + * ByteBuf} that contains at least enough bytes for one more such entry. These buffers are + * actually slices of the full metadata buffer, and this method doesn't move the full metadata + * buffer's {@link ByteBuf#readerIndex()}. As such, it requires the user to provide an {@code + * index} to read from. The next index is computed by calling {@link #computeNextEntryIndex(int, + * ByteBuf, ByteBuf)}. Size of the first buffer (the "header buffer") drives which decoding method + * should be further applied to it. + * + *

The header buffer is either: + * + *

    + *
  • made up of a single byte: this represents an encoded mime id, which can be further + * decoded using {@link #decodeMimeIdFromMimeBuffer(ByteBuf)} + *
  • made up of 2 or more bytes: this represents an encoded mime String + its length, which + * can be further decoded using {@link #decodeMimeTypeFromMimeBuffer(ByteBuf)}. Note the + * encoded length, in the first byte, is skipped by this decoding method because the + * remaining length of the buffer is that of the mime string. + *
+ * + * @param compositeMetadata the source {@link ByteBuf} that originally contains one or more + * metadata entries + * @param entryIndex the {@link ByteBuf#readerIndex()} to start decoding from. original reader + * index is kept on the source buffer + * @param retainSlices should produced metadata entry buffers {@link ByteBuf#slice() slices} be + * {@link ByteBuf#retainedSlice() retained}? + * @return a {@link ByteBuf} array of length 2 containing the mime header buffer + * slice and the content buffer slice, or one of the + * zero-length error constant arrays + */ + public static ByteBuf[] decodeMimeAndContentBuffersSlices( + ByteBuf compositeMetadata, int entryIndex, boolean retainSlices) { + compositeMetadata.markReaderIndex(); + compositeMetadata.readerIndex(entryIndex); + + if (compositeMetadata.isReadable()) { + ByteBuf mime; + int ridx = compositeMetadata.readerIndex(); + byte mimeIdOrLength = compositeMetadata.readByte(); + if ((mimeIdOrLength & STREAM_METADATA_KNOWN_MASK) == STREAM_METADATA_KNOWN_MASK) { + mime = + retainSlices + ? compositeMetadata.retainedSlice(ridx, 1) + : compositeMetadata.slice(ridx, 1); + } else { + // M flag unset, remaining 7 bits are the length of the mime + int mimeLength = Byte.toUnsignedInt(mimeIdOrLength) + 1; + + if (compositeMetadata.isReadable( + mimeLength)) { // need to be able to read an extra mimeLength bytes + // here we need a way for the returned ByteBuf to differentiate between a + // 1-byte length mime type and a 1 byte encoded mime id, preferably without + // re-applying the byte mask. The easiest way is to include the initial byte + // and have further decoding ignore the first byte. 1 byte buffer == id, 2+ byte + // buffer == full mime string. + mime = + retainSlices + ? + // we accommodate that we don't read from current readerIndex, but + // readerIndex - 1 ("0"), for a total slice size of mimeLength + 1 + compositeMetadata.retainedSlice(ridx, mimeLength + 1) + : compositeMetadata.slice(ridx, mimeLength + 1); + // we thus need to skip the bytes we just sliced, but not the flag/length byte + // which was already skipped in initial read + compositeMetadata.skipBytes(mimeLength); + } else { + compositeMetadata.resetReaderIndex(); + throw new IllegalStateException("metadata is malformed"); + } + } + + if (compositeMetadata.isReadable(3)) { + // ensures the length medium can be read + final int metadataLength = compositeMetadata.readUnsignedMedium(); + if (compositeMetadata.isReadable(metadataLength)) { + ByteBuf metadata = + retainSlices + ? compositeMetadata.readRetainedSlice(metadataLength) + : compositeMetadata.readSlice(metadataLength); + compositeMetadata.resetReaderIndex(); + return new ByteBuf[] {mime, metadata}; + } else { + compositeMetadata.resetReaderIndex(); + throw new IllegalStateException("metadata is malformed"); + } + } else { + compositeMetadata.resetReaderIndex(); + throw new IllegalStateException("metadata is malformed"); + } + } + compositeMetadata.resetReaderIndex(); + throw new IllegalArgumentException( + String.format("entry index %d is larger than buffer size", entryIndex)); + } + + /** + * Decode a {@code byte} compressed mime id from a {@link ByteBuf}, assuming said buffer properly + * contains such an id. + * + *

The buffer must have exactly one readable byte, which is assumed to have been tested for + * mime id encoding via the {@link #STREAM_METADATA_KNOWN_MASK} mask ({@code firstByte & + * STREAM_METADATA_KNOWN_MASK) == STREAM_METADATA_KNOWN_MASK}). + * + *

If there is no readable byte, the negative identifier of {@link + * WellKnownMimeType#UNPARSEABLE_MIME_TYPE} is returned. + * + * @param mimeBuffer the buffer that should next contain the compressed mime id byte + * @return the compressed mime id, between 0 and 127, or a negative id if the input is invalid + * @see #decodeMimeTypeFromMimeBuffer(ByteBuf) + */ + public static byte decodeMimeIdFromMimeBuffer(ByteBuf mimeBuffer) { + if (mimeBuffer.readableBytes() != 1) { + return WellKnownMimeType.UNPARSEABLE_MIME_TYPE.getIdentifier(); + } + return (byte) (mimeBuffer.readByte() & STREAM_METADATA_LENGTH_MASK); + } + + /** + * Decode a {@link CharSequence} custome mime type from a {@link ByteBuf}, assuming said buffer + * properly contains such a mime type. + * + *

The buffer must at least have two readable bytes, which distinguishes it from the {@link + * #decodeMimeIdFromMimeBuffer(ByteBuf) compressed id} case. The first byte is a size and the + * remaining bytes must correspond to the {@link CharSequence}, encoded fully in US_ASCII. As a + * result, the first byte can simply be skipped, and the remaining of the buffer be decoded to the + * mime type. + * + *

If the mime header buffer is less than 2 bytes long, returns {@code null}. + * + * @param flyweightMimeBuffer the mime header {@link ByteBuf} that contains length + custom mime + * type + * @return the decoded custom mime type, as a {@link CharSequence}, or null if the input is + * invalid + * @see #decodeMimeIdFromMimeBuffer(ByteBuf) + */ + @Nullable + public static CharSequence decodeMimeTypeFromMimeBuffer(ByteBuf flyweightMimeBuffer) { + if (flyweightMimeBuffer.readableBytes() < 2) { + throw new IllegalStateException("unable to decode explicit MIME type"); + } + // the encoded length is assumed to be kept at the start of the buffer + // but also assumed to be irrelevant because the rest of the slice length + // actually already matches _decoded_length + flyweightMimeBuffer.skipBytes(1); + int mimeStringLength = flyweightMimeBuffer.readableBytes(); + return flyweightMimeBuffer.readCharSequence(mimeStringLength, CharsetUtil.US_ASCII); + } + + /** + * Encode a new sub-metadata information into a composite metadata {@link CompositeByteBuf + * buffer}, without checking if the {@link String} can be matched with a well known compressable + * mime type. Prefer using this method and {@link #encodeAndAddMetadata(CompositeByteBuf, + * ByteBufAllocator, WellKnownMimeType, ByteBuf)} if you know in advance whether or not the mime + * is well known. Otherwise use {@link #encodeAndAddMetadataWithCompression(CompositeByteBuf, + * ByteBufAllocator, String, ByteBuf)} + * + * @param compositeMetaData the buffer that will hold all composite metadata information. + * @param allocator the {@link ByteBufAllocator} to use to create intermediate buffers as needed. + * @param customMimeType the custom mime type to encode. + * @param metadata the metadata value to encode. + */ + // see #encodeMetadataHeader(ByteBufAllocator, String, int) + public static void encodeAndAddMetadata( + CompositeByteBuf compositeMetaData, + ByteBufAllocator allocator, + String customMimeType, + ByteBuf metadata) { + compositeMetaData.addComponents( + true, encodeMetadataHeader(allocator, customMimeType, metadata.readableBytes()), metadata); + } + + /** + * Encode a new sub-metadata information into a composite metadata {@link CompositeByteBuf + * buffer}. + * + * @param compositeMetaData the buffer that will hold all composite metadata information. + * @param allocator the {@link ByteBufAllocator} to use to create intermediate buffers as needed. + * @param knownMimeType the {@link WellKnownMimeType} to encode. + * @param metadata the metadata value to encode. + */ + // see #encodeMetadataHeader(ByteBufAllocator, byte, int) + public static void encodeAndAddMetadata( + CompositeByteBuf compositeMetaData, + ByteBufAllocator allocator, + WellKnownMimeType knownMimeType, + ByteBuf metadata) { + compositeMetaData.addComponents( + true, + encodeMetadataHeader(allocator, knownMimeType.getIdentifier(), metadata.readableBytes()), + metadata); + } + + /** + * Encode a new sub-metadata information into a composite metadata {@link CompositeByteBuf + * buffer}, first verifying if the passed {@link String} matches a {@link WellKnownMimeType} (in + * which case it will be encoded in a compressed fashion using the mime id of that type). + * + *

Prefer using {@link #encodeAndAddMetadata(CompositeByteBuf, ByteBufAllocator, String, + * ByteBuf)} if you already know that the mime type is not a {@link WellKnownMimeType}. + * + * @param compositeMetaData the buffer that will hold all composite metadata information. + * @param allocator the {@link ByteBufAllocator} to use to create intermediate buffers as needed. + * @param mimeType the mime type to encode, as a {@link String}. well known mime types are + * compressed. + * @param metadata the metadata value to encode. + * @see #encodeAndAddMetadata(CompositeByteBuf, ByteBufAllocator, WellKnownMimeType, ByteBuf) + */ + // see #encodeMetadataHeader(ByteBufAllocator, String, int) + public static void encodeAndAddMetadataWithCompression( + CompositeByteBuf compositeMetaData, + ByteBufAllocator allocator, + String mimeType, + ByteBuf metadata) { + WellKnownMimeType wkn = WellKnownMimeType.fromString(mimeType); + if (wkn == WellKnownMimeType.UNPARSEABLE_MIME_TYPE) { + compositeMetaData.addComponents( + true, encodeMetadataHeader(allocator, mimeType, metadata.readableBytes()), metadata); + } else { + compositeMetaData.addComponents( + true, + encodeMetadataHeader(allocator, wkn.getIdentifier(), metadata.readableBytes()), + metadata); + } + } + + /** + * Returns whether there is another entry available at a given index + * + * @param compositeMetadata the buffer to inspect + * @param entryIndex the index to check at + * @return whether there is another entry available at a given index + */ + public static boolean hasEntry(ByteBuf compositeMetadata, int entryIndex) { + return compositeMetadata.writerIndex() - entryIndex > 0; + } + + /** + * Returns whether the header represents a well-known MIME type. + * + * @param header the header to inspect + * @return whether the header represents a well-known MIME type + */ + public static boolean isWellKnownMimeType(ByteBuf header) { + return header.readableBytes() == 1; + } + + /** + * Encode a new sub-metadata information into a composite metadata {@link CompositeByteBuf + * buffer}. + * + * @param compositeMetaData the buffer that will hold all composite metadata information. + * @param allocator the {@link ByteBufAllocator} to use to create intermediate buffers as needed. + * @param unknownCompressedMimeType the id of the {@link + * WellKnownMimeType#UNKNOWN_RESERVED_MIME_TYPE} to encode. + * @param metadata the metadata value to encode. + */ + // see #encodeMetadataHeader(ByteBufAllocator, byte, int) + static void encodeAndAddMetadata( + CompositeByteBuf compositeMetaData, + ByteBufAllocator allocator, + byte unknownCompressedMimeType, + ByteBuf metadata) { + compositeMetaData.addComponents( + true, + encodeMetadataHeader(allocator, unknownCompressedMimeType, metadata.readableBytes()), + metadata); + } + + /** + * Encode a custom mime type and a metadata value length into a newly allocated {@link ByteBuf}. + * + *

This larger representation encodes the mime type representation's length on a single byte, + * then the representation itself, then the unsigned metadata value length on 3 additional bytes. + * + * @param allocator the {@link ByteBufAllocator} to use to create the buffer. + * @param customMime a custom mime type to encode. + * @param metadataLength the metadata length to append to the buffer as an unsigned 24 bits + * integer. + * @return the encoded mime and metadata length information + */ + static ByteBuf encodeMetadataHeader( + ByteBufAllocator allocator, String customMime, int metadataLength) { + ByteBuf metadataHeader = allocator.buffer(4 + customMime.length()); + // reserve 1 byte for the customMime length + // /!\ careful not to read that first byte, which is random at this point + int writerIndexInitial = metadataHeader.writerIndex(); + metadataHeader.writerIndex(writerIndexInitial + 1); + + // write the custom mime in UTF8 but validate it is all ASCII-compatible + // (which produces the right result since ASCII chars are still encoded on 1 byte in UTF8) + int customMimeLength = ByteBufUtil.writeUtf8(metadataHeader, customMime); + if (!ByteBufUtil.isText( + metadataHeader, metadataHeader.readerIndex() + 1, customMimeLength, CharsetUtil.US_ASCII)) { + metadataHeader.release(); + throw new IllegalArgumentException("custom mime type must be US_ASCII characters only"); + } + if (customMimeLength < 1 || customMimeLength > 128) { + metadataHeader.release(); + throw new IllegalArgumentException( + "custom mime type must have a strictly positive length that fits on 7 unsigned bits, ie 1-128"); + } + metadataHeader.markWriterIndex(); + + // go back to beginning and write the length + // encoded length is one less than actual length, since 0 is never a valid length, which gives + // wider representation range + metadataHeader.writerIndex(writerIndexInitial); + metadataHeader.writeByte(customMimeLength - 1); + + // go back to post-mime type and write the metadata content length + metadataHeader.resetWriterIndex(); + NumberUtils.encodeUnsignedMedium(metadataHeader, metadataLength); + + return metadataHeader; + } + + /** + * Encode a {@link WellKnownMimeType well known mime type} and a metadata value length into a + * newly allocated {@link ByteBuf}. + * + *

This compact representation encodes the mime type via its ID on a single byte, and the + * unsigned value length on 3 additional bytes. + * + * @param allocator the {@link ByteBufAllocator} to use to create the buffer. + * @param mimeType a byte identifier of a {@link WellKnownMimeType} to encode. + * @param metadataLength the metadata length to append to the buffer as an unsigned 24 bits + * integer. + * @return the encoded mime and metadata length information + */ + static ByteBuf encodeMetadataHeader( + ByteBufAllocator allocator, byte mimeType, int metadataLength) { + ByteBuf buffer = allocator.buffer(4, 4).writeByte(mimeType | STREAM_METADATA_KNOWN_MASK); + + NumberUtils.encodeUnsignedMedium(buffer, metadataLength); + + return buffer; + } +} diff --git a/rsocket-core/src/main/java/io/rsocket/metadata/CompositeMetadataFlyweight.java b/rsocket-core/src/main/java/io/rsocket/metadata/CompositeMetadataFlyweight.java index 0520285c2..9916dfd3b 100644 --- a/rsocket-core/src/main/java/io/rsocket/metadata/CompositeMetadataFlyweight.java +++ b/rsocket-core/src/main/java/io/rsocket/metadata/CompositeMetadataFlyweight.java @@ -18,31 +18,25 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.ByteBufUtil; import io.netty.buffer.CompositeByteBuf; -import io.netty.util.CharsetUtil; -import io.rsocket.util.NumberUtils; import reactor.util.annotation.Nullable; /** * A flyweight class that can be used to encode/decode composite metadata information to/from {@link * ByteBuf}. This is intended for low-level efficient manipulation of such buffers. See {@link * CompositeMetadata} for an Iterator-like approach to decoding entries. + * + * @deprecated in favor of {@link CompositeMetadataCodec} */ +@Deprecated public class CompositeMetadataFlyweight { - static final int STREAM_METADATA_KNOWN_MASK = 0x80; // 1000 0000 - - static final byte STREAM_METADATA_LENGTH_MASK = 0x7F; // 0111 1111 - private CompositeMetadataFlyweight() {} public static int computeNextEntryIndex( int currentEntryIndex, ByteBuf headerSlice, ByteBuf contentSlice) { - return currentEntryIndex - + headerSlice.readableBytes() // this includes the mime length byte - + 3 // 3 bytes of the content length, which are excluded from the slice - + contentSlice.readableBytes(); + return CompositeMetadataCodec.computeNextEntryIndex( + currentEntryIndex, headerSlice, contentSlice); } /** @@ -77,67 +71,8 @@ public static int computeNextEntryIndex( */ public static ByteBuf[] decodeMimeAndContentBuffersSlices( ByteBuf compositeMetadata, int entryIndex, boolean retainSlices) { - compositeMetadata.markReaderIndex(); - compositeMetadata.readerIndex(entryIndex); - - if (compositeMetadata.isReadable()) { - ByteBuf mime; - int ridx = compositeMetadata.readerIndex(); - byte mimeIdOrLength = compositeMetadata.readByte(); - if ((mimeIdOrLength & STREAM_METADATA_KNOWN_MASK) == STREAM_METADATA_KNOWN_MASK) { - mime = - retainSlices - ? compositeMetadata.retainedSlice(ridx, 1) - : compositeMetadata.slice(ridx, 1); - } else { - // M flag unset, remaining 7 bits are the length of the mime - int mimeLength = Byte.toUnsignedInt(mimeIdOrLength) + 1; - - if (compositeMetadata.isReadable( - mimeLength)) { // need to be able to read an extra mimeLength bytes - // here we need a way for the returned ByteBuf to differentiate between a - // 1-byte length mime type and a 1 byte encoded mime id, preferably without - // re-applying the byte mask. The easiest way is to include the initial byte - // and have further decoding ignore the first byte. 1 byte buffer == id, 2+ byte - // buffer == full mime string. - mime = - retainSlices - ? - // we accommodate that we don't read from current readerIndex, but - // readerIndex - 1 ("0"), for a total slice size of mimeLength + 1 - compositeMetadata.retainedSlice(ridx, mimeLength + 1) - : compositeMetadata.slice(ridx, mimeLength + 1); - // we thus need to skip the bytes we just sliced, but not the flag/length byte - // which was already skipped in initial read - compositeMetadata.skipBytes(mimeLength); - } else { - compositeMetadata.resetReaderIndex(); - throw new IllegalStateException("metadata is malformed"); - } - } - - if (compositeMetadata.isReadable(3)) { - // ensures the length medium can be read - final int metadataLength = compositeMetadata.readUnsignedMedium(); - if (compositeMetadata.isReadable(metadataLength)) { - ByteBuf metadata = - retainSlices - ? compositeMetadata.readRetainedSlice(metadataLength) - : compositeMetadata.readSlice(metadataLength); - compositeMetadata.resetReaderIndex(); - return new ByteBuf[] {mime, metadata}; - } else { - compositeMetadata.resetReaderIndex(); - throw new IllegalStateException("metadata is malformed"); - } - } else { - compositeMetadata.resetReaderIndex(); - throw new IllegalStateException("metadata is malformed"); - } - } - compositeMetadata.resetReaderIndex(); - throw new IllegalArgumentException( - String.format("entry index %d is larger than buffer size", entryIndex)); + return CompositeMetadataCodec.decodeMimeAndContentBuffersSlices( + compositeMetadata, entryIndex, retainSlices); } /** @@ -145,8 +80,8 @@ public static ByteBuf[] decodeMimeAndContentBuffersSlices( * contains such an id. * *

The buffer must have exactly one readable byte, which is assumed to have been tested for - * mime id encoding via the {@link #STREAM_METADATA_KNOWN_MASK} mask ({@code firstByte & - * STREAM_METADATA_KNOWN_MASK) == STREAM_METADATA_KNOWN_MASK}). + * mime id encoding via the {@link CompositeMetadataCodec#STREAM_METADATA_KNOWN_MASK} mask ({@code + * firstByte & STREAM_METADATA_KNOWN_MASK) == STREAM_METADATA_KNOWN_MASK}). * *

If there is no readable byte, the negative identifier of {@link * WellKnownMimeType#UNPARSEABLE_MIME_TYPE} is returned. @@ -156,10 +91,7 @@ public static ByteBuf[] decodeMimeAndContentBuffersSlices( * @see #decodeMimeTypeFromMimeBuffer(ByteBuf) */ public static byte decodeMimeIdFromMimeBuffer(ByteBuf mimeBuffer) { - if (mimeBuffer.readableBytes() != 1) { - return WellKnownMimeType.UNPARSEABLE_MIME_TYPE.getIdentifier(); - } - return (byte) (mimeBuffer.readByte() & STREAM_METADATA_LENGTH_MASK); + return CompositeMetadataCodec.decodeMimeIdFromMimeBuffer(mimeBuffer); } /** @@ -182,15 +114,7 @@ public static byte decodeMimeIdFromMimeBuffer(ByteBuf mimeBuffer) { */ @Nullable public static CharSequence decodeMimeTypeFromMimeBuffer(ByteBuf flyweightMimeBuffer) { - if (flyweightMimeBuffer.readableBytes() < 2) { - throw new IllegalStateException("unable to decode explicit MIME type"); - } - // the encoded length is assumed to be kept at the start of the buffer - // but also assumed to be irrelevant because the rest of the slice length - // actually already matches _decoded_length - flyweightMimeBuffer.skipBytes(1); - int mimeStringLength = flyweightMimeBuffer.readableBytes(); - return flyweightMimeBuffer.readCharSequence(mimeStringLength, CharsetUtil.US_ASCII); + return CompositeMetadataCodec.decodeMimeTypeFromMimeBuffer(flyweightMimeBuffer); } /** @@ -212,8 +136,8 @@ public static void encodeAndAddMetadata( ByteBufAllocator allocator, String customMimeType, ByteBuf metadata) { - compositeMetaData.addComponents( - true, encodeMetadataHeader(allocator, customMimeType, metadata.readableBytes()), metadata); + CompositeMetadataCodec.encodeAndAddMetadata( + compositeMetaData, allocator, customMimeType, metadata); } /** @@ -231,10 +155,8 @@ public static void encodeAndAddMetadata( ByteBufAllocator allocator, WellKnownMimeType knownMimeType, ByteBuf metadata) { - compositeMetaData.addComponents( - true, - encodeMetadataHeader(allocator, knownMimeType.getIdentifier(), metadata.readableBytes()), - metadata); + CompositeMetadataCodec.encodeAndAddMetadata( + compositeMetaData, allocator, knownMimeType, metadata); } /** @@ -258,16 +180,8 @@ public static void encodeAndAddMetadataWithCompression( ByteBufAllocator allocator, String mimeType, ByteBuf metadata) { - WellKnownMimeType wkn = WellKnownMimeType.fromString(mimeType); - if (wkn == WellKnownMimeType.UNPARSEABLE_MIME_TYPE) { - compositeMetaData.addComponents( - true, encodeMetadataHeader(allocator, mimeType, metadata.readableBytes()), metadata); - } else { - compositeMetaData.addComponents( - true, - encodeMetadataHeader(allocator, wkn.getIdentifier(), metadata.readableBytes()), - metadata); - } + CompositeMetadataCodec.encodeAndAddMetadataWithCompression( + compositeMetaData, allocator, mimeType, metadata); } /** @@ -278,7 +192,7 @@ public static void encodeAndAddMetadataWithCompression( * @return whether there is another entry available at a given index */ public static boolean hasEntry(ByteBuf compositeMetadata, int entryIndex) { - return compositeMetadata.writerIndex() - entryIndex > 0; + return CompositeMetadataCodec.hasEntry(compositeMetadata, entryIndex); } /** @@ -288,7 +202,7 @@ public static boolean hasEntry(ByteBuf compositeMetadata, int entryIndex) { * @return whether the header represents a well-known MIME type */ public static boolean isWellKnownMimeType(ByteBuf header) { - return header.readableBytes() == 1; + return CompositeMetadataCodec.isWellKnownMimeType(header); } /** @@ -307,10 +221,8 @@ static void encodeAndAddMetadata( ByteBufAllocator allocator, byte unknownCompressedMimeType, ByteBuf metadata) { - compositeMetaData.addComponents( - true, - encodeMetadataHeader(allocator, unknownCompressedMimeType, metadata.readableBytes()), - metadata); + CompositeMetadataCodec.encodeAndAddMetadata( + compositeMetaData, allocator, unknownCompressedMimeType, metadata); } /** @@ -327,38 +239,7 @@ static void encodeAndAddMetadata( */ static ByteBuf encodeMetadataHeader( ByteBufAllocator allocator, String customMime, int metadataLength) { - ByteBuf metadataHeader = allocator.buffer(4 + customMime.length()); - // reserve 1 byte for the customMime length - // /!\ careful not to read that first byte, which is random at this point - int writerIndexInitial = metadataHeader.writerIndex(); - metadataHeader.writerIndex(writerIndexInitial + 1); - - // write the custom mime in UTF8 but validate it is all ASCII-compatible - // (which produces the right result since ASCII chars are still encoded on 1 byte in UTF8) - int customMimeLength = ByteBufUtil.writeUtf8(metadataHeader, customMime); - if (!ByteBufUtil.isText( - metadataHeader, metadataHeader.readerIndex() + 1, customMimeLength, CharsetUtil.US_ASCII)) { - metadataHeader.release(); - throw new IllegalArgumentException("custom mime type must be US_ASCII characters only"); - } - if (customMimeLength < 1 || customMimeLength > 128) { - metadataHeader.release(); - throw new IllegalArgumentException( - "custom mime type must have a strictly positive length that fits on 7 unsigned bits, ie 1-128"); - } - metadataHeader.markWriterIndex(); - - // go back to beginning and write the length - // encoded length is one less than actual length, since 0 is never a valid length, which gives - // wider representation range - metadataHeader.writerIndex(writerIndexInitial); - metadataHeader.writeByte(customMimeLength - 1); - - // go back to post-mime type and write the metadata content length - metadataHeader.resetWriterIndex(); - NumberUtils.encodeUnsignedMedium(metadataHeader, metadataLength); - - return metadataHeader; + return CompositeMetadataCodec.encodeMetadataHeader(allocator, customMime, metadataLength); } /** @@ -376,10 +257,6 @@ static ByteBuf encodeMetadataHeader( */ static ByteBuf encodeMetadataHeader( ByteBufAllocator allocator, byte mimeType, int metadataLength) { - ByteBuf buffer = allocator.buffer(4, 4).writeByte(mimeType | STREAM_METADATA_KNOWN_MASK); - - NumberUtils.encodeUnsignedMedium(buffer, metadataLength); - - return buffer; + return CompositeMetadataCodec.encodeMetadataHeader(allocator, mimeType, metadataLength); } } diff --git a/rsocket-core/src/main/java/io/rsocket/metadata/TaggingMetadataCodec.java b/rsocket-core/src/main/java/io/rsocket/metadata/TaggingMetadataCodec.java new file mode 100644 index 000000000..d766cf59f --- /dev/null +++ b/rsocket-core/src/main/java/io/rsocket/metadata/TaggingMetadataCodec.java @@ -0,0 +1,76 @@ +package io.rsocket.metadata; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.CompositeByteBuf; +import java.nio.charset.StandardCharsets; +import java.util.Collection; + +/** + * A flyweight class that can be used to encode/decode tagging metadata information to/from {@link + * ByteBuf}. This is intended for low-level efficient manipulation of such buffers. See {@link + * TaggingMetadata} for an Iterator-like approach to decoding entries. + * + * @author linux_china + */ +public class TaggingMetadataCodec { + /** Tag max length in bytes */ + private static int TAG_LENGTH_MAX = 0xFF; + + /** + * create routing metadata + * + * @param allocator the {@link ByteBufAllocator} to use to create intermediate buffers as needed. + * @param tags tag values + * @return routing metadata + */ + public static RoutingMetadata createRoutingMetadata( + ByteBufAllocator allocator, Collection tags) { + return new RoutingMetadata(createTaggingContent(allocator, tags)); + } + + /** + * create tagging metadata from composite metadata entry + * + * @param entry composite metadata entry + * @return tagging metadata + */ + public static TaggingMetadata createTaggingMetadata(CompositeMetadata.Entry entry) { + return new TaggingMetadata(entry.getMimeType(), entry.getContent()); + } + + /** + * create tagging metadata + * + * @param allocator the {@link ByteBufAllocator} to use to create intermediate buffers as needed. + * @param knownMimeType the {@link WellKnownMimeType} to encode. + * @param tags tag values + * @return Tagging Metadata + */ + public static TaggingMetadata createTaggingMetadata( + ByteBufAllocator allocator, String knownMimeType, Collection tags) { + return new TaggingMetadata(knownMimeType, createTaggingContent(allocator, tags)); + } + + /** + * create tagging content + * + * @param allocator the {@link ByteBufAllocator} to use to create intermediate buffers as needed. + * @param tags tag values + * @return tagging content + */ + public static ByteBuf createTaggingContent(ByteBufAllocator allocator, Collection tags) { + CompositeByteBuf taggingContent = allocator.compositeBuffer(); + for (String key : tags) { + int length = ByteBufUtil.utf8Bytes(key); + if (length == 0 || length > TAG_LENGTH_MAX) { + continue; + } + ByteBuf byteBuf = allocator.buffer().writeByte(length); + byteBuf.writeCharSequence(key, StandardCharsets.UTF_8); + taggingContent.addComponent(true, byteBuf); + } + return taggingContent; + } +} diff --git a/rsocket-core/src/main/java/io/rsocket/metadata/TaggingMetadataFlyweight.java b/rsocket-core/src/main/java/io/rsocket/metadata/TaggingMetadataFlyweight.java index c7870bf0d..718528358 100644 --- a/rsocket-core/src/main/java/io/rsocket/metadata/TaggingMetadataFlyweight.java +++ b/rsocket-core/src/main/java/io/rsocket/metadata/TaggingMetadataFlyweight.java @@ -2,9 +2,6 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.CompositeByteBuf; -import java.nio.charset.StandardCharsets; import java.util.Collection; /** @@ -12,12 +9,11 @@ * ByteBuf}. This is intended for low-level efficient manipulation of such buffers. See {@link * TaggingMetadata} for an Iterator-like approach to decoding entries. * + * @deprecated in favor of {@link TaggingMetadataCodec} * @author linux_china */ +@Deprecated public class TaggingMetadataFlyweight { - /** Tag max length in bytes */ - private static int TAG_LENGTH_MAX = 0xFF; - /** * create routing metadata * @@ -27,7 +23,7 @@ public class TaggingMetadataFlyweight { */ public static RoutingMetadata createRoutingMetadata( ByteBufAllocator allocator, Collection tags) { - return new RoutingMetadata(createTaggingContent(allocator, tags)); + return TaggingMetadataCodec.createRoutingMetadata(allocator, tags); } /** @@ -37,7 +33,7 @@ public static RoutingMetadata createRoutingMetadata( * @return tagging metadata */ public static TaggingMetadata createTaggingMetadata(CompositeMetadata.Entry entry) { - return new TaggingMetadata(entry.getMimeType(), entry.getContent()); + return TaggingMetadataCodec.createTaggingMetadata(entry); } /** @@ -50,7 +46,7 @@ public static TaggingMetadata createTaggingMetadata(CompositeMetadata.Entry entr */ public static TaggingMetadata createTaggingMetadata( ByteBufAllocator allocator, String knownMimeType, Collection tags) { - return new TaggingMetadata(knownMimeType, createTaggingContent(allocator, tags)); + return TaggingMetadataCodec.createTaggingMetadata(allocator, knownMimeType, tags); } /** @@ -61,16 +57,6 @@ public static TaggingMetadata createTaggingMetadata( * @return tagging content */ public static ByteBuf createTaggingContent(ByteBufAllocator allocator, Collection tags) { - CompositeByteBuf taggingContent = allocator.compositeBuffer(); - for (String key : tags) { - int length = ByteBufUtil.utf8Bytes(key); - if (length == 0 || length > TAG_LENGTH_MAX) { - continue; - } - ByteBuf byteBuf = allocator.buffer().writeByte(length); - byteBuf.writeCharSequence(key, StandardCharsets.UTF_8); - taggingContent.addComponent(true, byteBuf); - } - return taggingContent; + return TaggingMetadataCodec.createTaggingContent(allocator, tags); } } diff --git a/rsocket-core/src/main/java/io/rsocket/metadata/WellKnownAuthType.java b/rsocket-core/src/main/java/io/rsocket/metadata/WellKnownAuthType.java new file mode 100644 index 000000000..66c98701c --- /dev/null +++ b/rsocket-core/src/main/java/io/rsocket/metadata/WellKnownAuthType.java @@ -0,0 +1,121 @@ +/* + * Copyright 2015-2018 the original author or authors. + * + * Licensed 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 io.rsocket.metadata; + +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Enumeration of Well Known Auth Types, as defined in the eponymous extension. Such auth types are + * used in composite metadata (which can include routing and/or tracing metadata). Per + * specification, identifiers are between 0 and 127 (inclusive). + */ +public enum WellKnownAuthType { + UNPARSEABLE_AUTH_TYPE("UNPARSEABLE_AUTH_TYPE_DO_NOT_USE", (byte) -2), + UNKNOWN_RESERVED_AUTH_TYPE("UNKNOWN_YET_RESERVED_DO_NOT_USE", (byte) -1), + + SIMPLE("simple", (byte) 0x00), + BEARER("bearer", (byte) 0x01); + // ... reserved for future use ... + + static final WellKnownAuthType[] TYPES_BY_AUTH_ID; + static final Map TYPES_BY_AUTH_STRING; + + static { + // precompute an array of all valid auth ids, filling the blanks with the RESERVED enum + TYPES_BY_AUTH_ID = new WellKnownAuthType[128]; // 0-127 inclusive + Arrays.fill(TYPES_BY_AUTH_ID, UNKNOWN_RESERVED_AUTH_TYPE); + // also prepare a Map of the types by auth string + TYPES_BY_AUTH_STRING = new LinkedHashMap<>(128); + + for (WellKnownAuthType value : values()) { + if (value.getIdentifier() >= 0) { + TYPES_BY_AUTH_ID[value.getIdentifier()] = value; + TYPES_BY_AUTH_STRING.put(value.getString(), value); + } + } + } + + private final byte identifier; + private final String str; + + WellKnownAuthType(String str, byte identifier) { + this.str = str; + this.identifier = identifier; + } + + /** + * Find the {@link WellKnownAuthType} for the given identifier (as an {@code int}). Valid + * identifiers are defined to be integers between 0 and 127, inclusive. Identifiers outside of + * this range will produce the {@link #UNPARSEABLE_AUTH_TYPE}. Additionally, some identifiers in + * that range are still only reserved and don't have a type associated yet: this method returns + * the {@link #UNKNOWN_RESERVED_AUTH_TYPE} when passing such an identifier, which lets call sites + * potentially detect this and keep the original representation when transmitting the associated + * metadata buffer. + * + * @param id the looked up identifier + * @return the {@link WellKnownAuthType}, or {@link #UNKNOWN_RESERVED_AUTH_TYPE} if the id is out + * of the specification's range, or {@link #UNKNOWN_RESERVED_AUTH_TYPE} if the id is one that + * is merely reserved but unknown to this implementation. + */ + public static WellKnownAuthType fromIdentifier(int id) { + if (id < 0x00 || id > 0x7F) { + return UNPARSEABLE_AUTH_TYPE; + } + return TYPES_BY_AUTH_ID[id]; + } + + /** + * Find the {@link WellKnownAuthType} for the given {@link String} representation. If the + * representation is {@code null} or doesn't match a {@link WellKnownAuthType}, the {@link + * #UNPARSEABLE_AUTH_TYPE} is returned. + * + * @param authType the looked up auth type + * @return the matching {@link WellKnownAuthType}, or {@link #UNPARSEABLE_AUTH_TYPE} if none + * matches + */ + public static WellKnownAuthType fromString(String authType) { + if (authType == null) throw new IllegalArgumentException("type must be non-null"); + + // force UNPARSEABLE if by chance UNKNOWN_RESERVED_AUTH_TYPE's text has been used + if (authType.equals(UNKNOWN_RESERVED_AUTH_TYPE.str)) { + return UNPARSEABLE_AUTH_TYPE; + } + + return TYPES_BY_AUTH_STRING.getOrDefault(authType, UNPARSEABLE_AUTH_TYPE); + } + + /** @return the byte identifier of the auth type, guaranteed to be positive or zero. */ + public byte getIdentifier() { + return identifier; + } + + /** + * @return the auth type represented as a {@link String}, which is made of US_ASCII compatible + * characters only + */ + public String getString() { + return str; + } + + /** @see #getString() */ + @Override + public String toString() { + return str; + } +} diff --git a/rsocket-core/src/main/java/io/rsocket/metadata/security/AuthMetadataFlyweight.java b/rsocket-core/src/main/java/io/rsocket/metadata/security/AuthMetadataFlyweight.java index 27bf4d1da..fd990d273 100644 --- a/rsocket-core/src/main/java/io/rsocket/metadata/security/AuthMetadataFlyweight.java +++ b/rsocket-core/src/main/java/io/rsocket/metadata/security/AuthMetadataFlyweight.java @@ -2,20 +2,14 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; -import io.netty.util.CharsetUtil; -import io.rsocket.util.CharByteBufUtil; +import io.rsocket.metadata.AuthMetadataCodec; +/** @deprecated in favor of {@link io.rsocket.metadata.AuthMetadataCodec} */ +@Deprecated public class AuthMetadataFlyweight { static final int STREAM_METADATA_KNOWN_MASK = 0x80; // 1000 0000 - static final byte STREAM_METADATA_LENGTH_MASK = 0x7F; // 0111 1111 - - static final int USERNAME_BYTES_LENGTH = 1; - static final int AUTH_TYPE_ID_LENGTH = 1; - - static final char[] EMPTY_CHARS_ARRAY = new char[0]; private AuthMetadataFlyweight() {} @@ -31,24 +25,7 @@ private AuthMetadataFlyweight() {} public static ByteBuf encodeMetadata( ByteBufAllocator allocator, String customAuthType, ByteBuf metadata) { - int actualASCIILength = ByteBufUtil.utf8Bytes(customAuthType); - if (actualASCIILength != customAuthType.length()) { - throw new IllegalArgumentException("custom auth type must be US_ASCII characters only"); - } - if (actualASCIILength < 1 || actualASCIILength > 128) { - throw new IllegalArgumentException( - "custom auth type must have a strictly positive length that fits on 7 unsigned bits, ie 1-128"); - } - - int capacity = 1 + actualASCIILength; - ByteBuf headerBuffer = allocator.buffer(capacity, capacity); - // encoded length is one less than actual length, since 0 is never a valid length, which gives - // wider representation range - headerBuffer.writeByte(actualASCIILength - 1); - - ByteBufUtil.reserveAndWriteUtf8(headerBuffer, customAuthType, actualASCIILength); - - return allocator.compositeBuffer(2).addComponents(true, headerBuffer, metadata); + return AuthMetadataCodec.encodeMetadata(allocator, customAuthType, metadata); } /** @@ -64,18 +41,7 @@ public static ByteBuf encodeMetadata( public static ByteBuf encodeMetadata( ByteBufAllocator allocator, WellKnownAuthType authType, ByteBuf metadata) { - if (authType == WellKnownAuthType.UNPARSEABLE_AUTH_TYPE - || authType == WellKnownAuthType.UNKNOWN_RESERVED_AUTH_TYPE) { - throw new IllegalArgumentException("only allowed AuthType should be used"); - } - - int capacity = AUTH_TYPE_ID_LENGTH; - ByteBuf headerBuffer = - allocator - .buffer(capacity, capacity) - .writeByte(authType.getIdentifier() | STREAM_METADATA_KNOWN_MASK); - - return allocator.compositeBuffer(2).addComponents(true, headerBuffer, metadata); + return AuthMetadataCodec.encodeMetadata(allocator, WellKnownAuthType.cast(authType), metadata); } /** @@ -88,25 +54,7 @@ public static ByteBuf encodeMetadata( */ public static ByteBuf encodeSimpleMetadata( ByteBufAllocator allocator, char[] username, char[] password) { - - int usernameLength = CharByteBufUtil.utf8Bytes(username); - if (usernameLength > 255) { - throw new IllegalArgumentException( - "Username should be shorter than or equal to 255 bytes length in UTF-8 encoding"); - } - - int passwordLength = CharByteBufUtil.utf8Bytes(password); - int capacity = AUTH_TYPE_ID_LENGTH + USERNAME_BYTES_LENGTH + usernameLength + passwordLength; - final ByteBuf buffer = - allocator - .buffer(capacity, capacity) - .writeByte(WellKnownAuthType.SIMPLE.getIdentifier() | STREAM_METADATA_KNOWN_MASK) - .writeByte(usernameLength); - - CharByteBufUtil.writeUtf8(buffer, username); - CharByteBufUtil.writeUtf8(buffer, password); - - return buffer; + return AuthMetadataCodec.encodeSimpleMetadata(allocator, username, password); } /** @@ -116,17 +64,7 @@ public static ByteBuf encodeSimpleMetadata( * @param token the char sequence which represents BEARER token. */ public static ByteBuf encodeBearerMetadata(ByteBufAllocator allocator, char[] token) { - - int tokenLength = CharByteBufUtil.utf8Bytes(token); - int capacity = AUTH_TYPE_ID_LENGTH + tokenLength; - final ByteBuf buffer = - allocator - .buffer(capacity, capacity) - .writeByte(WellKnownAuthType.BEARER.getIdentifier() | STREAM_METADATA_KNOWN_MASK); - - CharByteBufUtil.writeUtf8(buffer, token); - - return buffer; + return AuthMetadataCodec.encodeBearerMetadata(allocator, token); } /** @@ -146,12 +84,7 @@ public static ByteBuf encodeBearerMetadata(ByteBufAllocator allocator, char[] to */ public static ByteBuf encodeMetadataWithCompression( ByteBufAllocator allocator, String authType, ByteBuf metadata) { - WellKnownAuthType wkn = WellKnownAuthType.fromString(authType); - if (wkn == WellKnownAuthType.UNPARSEABLE_AUTH_TYPE) { - return AuthMetadataFlyweight.encodeMetadata(allocator, authType, metadata); - } else { - return AuthMetadataFlyweight.encodeMetadata(allocator, wkn, metadata); - } + return AuthMetadataCodec.encodeMetadataWithCompression(allocator, authType, metadata); } /** @@ -161,8 +94,7 @@ public static ByteBuf encodeMetadataWithCompression( * @param metadata byteBuf used to get information from */ public static boolean isWellKnownAuthType(ByteBuf metadata) { - byte lengthOrId = metadata.getByte(0); - return (lengthOrId & STREAM_METADATA_LENGTH_MASK) != lengthOrId; + return AuthMetadataCodec.isWellKnownAuthType(metadata); } /** @@ -175,18 +107,7 @@ public static boolean isWellKnownAuthType(ByteBuf metadata) { * @throws IllegalStateException if not enough readable bytes in the given {@link ByteBuf} */ public static WellKnownAuthType decodeWellKnownAuthType(ByteBuf metadata) { - if (metadata.readableBytes() < 1) { - throw new IllegalStateException( - "Unable to decode Well Know Auth type. Not enough readable bytes"); - } - byte lengthOrId = metadata.readByte(); - int normalizedId = (byte) (lengthOrId & STREAM_METADATA_LENGTH_MASK); - - if (normalizedId != lengthOrId) { - return WellKnownAuthType.fromIdentifier(normalizedId); - } - - return WellKnownAuthType.UNPARSEABLE_AUTH_TYPE; + return WellKnownAuthType.cast(AuthMetadataCodec.decodeWellKnownAuthType(metadata)); } /** @@ -196,25 +117,7 @@ public static WellKnownAuthType decodeWellKnownAuthType(ByteBuf metadata) { * @return */ public static CharSequence decodeCustomAuthType(ByteBuf metadata) { - if (metadata.readableBytes() < 2) { - throw new IllegalStateException( - "Unable to decode custom Auth type. Not enough readable bytes"); - } - - byte encodedLength = metadata.readByte(); - if (encodedLength < 0) { - throw new IllegalStateException( - "Unable to decode custom Auth type. Incorrect auth type length"); - } - - // encoded length is realLength - 1 in order to avoid intersection with 0x00 authtype - int realLength = encodedLength + 1; - if (metadata.readableBytes() < realLength) { - throw new IllegalArgumentException( - "Unable to decode custom Auth type. Malformed length or auth type string"); - } - - return metadata.readCharSequence(realLength, CharsetUtil.US_ASCII); + return AuthMetadataCodec.decodeCustomAuthType(metadata); } /** @@ -227,11 +130,7 @@ public static CharSequence decodeCustomAuthType(ByteBuf metadata) { * given one */ public static ByteBuf decodePayload(ByteBuf metadata) { - if (metadata.readableBytes() == 0) { - return Unpooled.EMPTY_BUFFER; - } - - return metadata.readSlice(metadata.readableBytes()); + return AuthMetadataCodec.decodePayload(metadata); } /** @@ -243,13 +142,7 @@ public static ByteBuf decodePayload(ByteBuf metadata) { * @return sliced {@link ByteBuf} or {@link Unpooled#EMPTY_BUFFER} if username length is zero */ public static ByteBuf decodeUsername(ByteBuf simpleAuthMetadata) { - short usernameLength = decodeUsernameLength(simpleAuthMetadata); - - if (usernameLength == 0) { - return Unpooled.EMPTY_BUFFER; - } - - return simpleAuthMetadata.readSlice(usernameLength); + return AuthMetadataCodec.decodeUsername(simpleAuthMetadata); } /** @@ -261,11 +154,7 @@ public static ByteBuf decodeUsername(ByteBuf simpleAuthMetadata) { * @return sliced {@link ByteBuf} or {@link Unpooled#EMPTY_BUFFER} if password length is zero */ public static ByteBuf decodePassword(ByteBuf simpleAuthMetadata) { - if (simpleAuthMetadata.readableBytes() == 0) { - return Unpooled.EMPTY_BUFFER; - } - - return simpleAuthMetadata.readSlice(simpleAuthMetadata.readableBytes()); + return AuthMetadataCodec.decodePassword(simpleAuthMetadata); } /** * Read up to 257 {@code bytes} from the given {@link ByteBuf} where the first byte is username @@ -276,13 +165,7 @@ public static ByteBuf decodePassword(ByteBuf simpleAuthMetadata) { * @return {@code char[]} which represents UTF-8 username */ public static char[] decodeUsernameAsCharArray(ByteBuf simpleAuthMetadata) { - short usernameLength = decodeUsernameLength(simpleAuthMetadata); - - if (usernameLength == 0) { - return EMPTY_CHARS_ARRAY; - } - - return CharByteBufUtil.readUtf8(simpleAuthMetadata, usernameLength); + return AuthMetadataCodec.decodeUsernameAsCharArray(simpleAuthMetadata); } /** @@ -294,11 +177,7 @@ public static char[] decodeUsernameAsCharArray(ByteBuf simpleAuthMetadata) { * @return {@code char[]} which represents UTF-8 password */ public static char[] decodePasswordAsCharArray(ByteBuf simpleAuthMetadata) { - if (simpleAuthMetadata.readableBytes() == 0) { - return EMPTY_CHARS_ARRAY; - } - - return CharByteBufUtil.readUtf8(simpleAuthMetadata, simpleAuthMetadata.readableBytes()); + return AuthMetadataCodec.decodePasswordAsCharArray(simpleAuthMetadata); } /** @@ -310,26 +189,6 @@ public static char[] decodePasswordAsCharArray(ByteBuf simpleAuthMetadata) { * @return {@code char[]} which represents UTF-8 password */ public static char[] decodeBearerTokenAsCharArray(ByteBuf bearerAuthMetadata) { - if (bearerAuthMetadata.readableBytes() == 0) { - return EMPTY_CHARS_ARRAY; - } - - return CharByteBufUtil.readUtf8(bearerAuthMetadata, bearerAuthMetadata.readableBytes()); - } - - private static short decodeUsernameLength(ByteBuf simpleAuthMetadata) { - if (simpleAuthMetadata.readableBytes() < 1) { - throw new IllegalStateException( - "Unable to decode custom username. Not enough readable bytes"); - } - - short usernameLength = simpleAuthMetadata.readUnsignedByte(); - - if (simpleAuthMetadata.readableBytes() < usernameLength) { - throw new IllegalArgumentException( - "Unable to decode username. Malformed username length or content"); - } - - return usernameLength; + return AuthMetadataCodec.decodeBearerTokenAsCharArray(bearerAuthMetadata); } } diff --git a/rsocket-core/src/main/java/io/rsocket/metadata/security/WellKnownAuthType.java b/rsocket-core/src/main/java/io/rsocket/metadata/security/WellKnownAuthType.java index bd4b656b8..24e5ff0db 100644 --- a/rsocket-core/src/main/java/io/rsocket/metadata/security/WellKnownAuthType.java +++ b/rsocket-core/src/main/java/io/rsocket/metadata/security/WellKnownAuthType.java @@ -24,7 +24,10 @@ * Enumeration of Well Known Auth Types, as defined in the eponymous extension. Such auth types are * used in composite metadata (which can include routing and/or tracing metadata). Per * specification, identifiers are between 0 and 127 (inclusive). + * + * @deprecated in favor of {@link io.rsocket.metadata.WellKnownAuthType} */ +@Deprecated public enum WellKnownAuthType { UNPARSEABLE_AUTH_TYPE("UNPARSEABLE_AUTH_TYPE_DO_NOT_USE", (byte) -2), UNKNOWN_RESERVED_AUTH_TYPE("UNKNOWN_YET_RESERVED_DO_NOT_USE", (byte) -1), @@ -59,6 +62,29 @@ public enum WellKnownAuthType { this.identifier = identifier; } + static io.rsocket.metadata.WellKnownAuthType cast(WellKnownAuthType wellKnownAuthType) { + byte identifier = wellKnownAuthType.identifier; + if (identifier == io.rsocket.metadata.WellKnownAuthType.UNPARSEABLE_AUTH_TYPE.getIdentifier()) { + return io.rsocket.metadata.WellKnownAuthType.UNPARSEABLE_AUTH_TYPE; + } else if (identifier + == io.rsocket.metadata.WellKnownAuthType.UNKNOWN_RESERVED_AUTH_TYPE.getIdentifier()) { + return io.rsocket.metadata.WellKnownAuthType.UNKNOWN_RESERVED_AUTH_TYPE; + } else { + return io.rsocket.metadata.WellKnownAuthType.fromIdentifier(identifier); + } + } + + static WellKnownAuthType cast(io.rsocket.metadata.WellKnownAuthType wellKnownAuthType) { + byte identifier = wellKnownAuthType.getIdentifier(); + if (identifier == WellKnownAuthType.UNPARSEABLE_AUTH_TYPE.identifier) { + return WellKnownAuthType.UNPARSEABLE_AUTH_TYPE; + } else if (identifier == WellKnownAuthType.UNKNOWN_RESERVED_AUTH_TYPE.identifier) { + return WellKnownAuthType.UNKNOWN_RESERVED_AUTH_TYPE; + } else { + return TYPES_BY_AUTH_ID[identifier]; + } + } + /** * Find the {@link WellKnownAuthType} for the given identifier (as an {@code int}). Valid * identifiers are defined to be integers between 0 and 127, inclusive. Identifiers outside of diff --git a/rsocket-core/src/main/java/io/rsocket/resume/ClientRSocketSession.java b/rsocket-core/src/main/java/io/rsocket/resume/ClientRSocketSession.java index 01b6dfeae..ed9450357 100644 --- a/rsocket-core/src/main/java/io/rsocket/resume/ClientRSocketSession.java +++ b/rsocket-core/src/main/java/io/rsocket/resume/ClientRSocketSession.java @@ -20,9 +20,9 @@ import io.netty.buffer.ByteBufAllocator; import io.rsocket.DuplexConnection; import io.rsocket.exceptions.ConnectionErrorException; -import io.rsocket.frame.ErrorFrameFlyweight; -import io.rsocket.frame.ResumeFrameFlyweight; -import io.rsocket.frame.ResumeOkFrameFlyweight; +import io.rsocket.frame.ErrorFrameCodec; +import io.rsocket.frame.ResumeFrameCodec; +import io.rsocket.frame.ResumeOkFrameCodec; import io.rsocket.internal.ClientServerInputMultiplexer; import java.time.Duration; import java.util.concurrent.atomic.AtomicBoolean; @@ -86,7 +86,7 @@ public ClientRSocketSession( position); /*Connection is established again: send RESUME frame to server, listen for RESUME_OK*/ sendFrame( - ResumeFrameFlyweight.encode( + ResumeFrameCodec.encode( allocator, /*retain so token is not released once sent as part of resume frame*/ resumeToken.retain(), @@ -123,7 +123,7 @@ public ClientRSocketSession resumeWith(ByteBuf resumeOkFrame) { .onErrorResume( err -> sendFrame( - ErrorFrameFlyweight.encode( + ErrorFrameCodec.encode( allocator, 0, errorFrameThrowable(remoteImpliedPos))) .then(Mono.fromRunnable(resumableConnection::dispose)) /*Resumption is impossible: no need to return control to ResumableConnection*/ @@ -157,7 +157,7 @@ private Mono sendFrame(ByteBuf frame) { } private static long remoteImpliedPos(ByteBuf resumeOkFrame) { - return ResumeOkFrameFlyweight.lastReceivedClientPos(resumeOkFrame); + return ResumeOkFrameCodec.lastReceivedClientPos(resumeOkFrame); } private static long remotePos(ByteBuf resumeOkFrame) { diff --git a/rsocket-core/src/main/java/io/rsocket/resume/ResumableDuplexConnection.java b/rsocket-core/src/main/java/io/rsocket/resume/ResumableDuplexConnection.java index 980de2de1..461d71228 100644 --- a/rsocket-core/src/main/java/io/rsocket/resume/ResumableDuplexConnection.java +++ b/rsocket-core/src/main/java/io/rsocket/resume/ResumableDuplexConnection.java @@ -20,7 +20,7 @@ import io.netty.buffer.ByteBufAllocator; import io.rsocket.Closeable; import io.rsocket.DuplexConnection; -import io.rsocket.frame.FrameHeaderFlyweight; +import io.rsocket.frame.FrameHeaderCodec; import java.nio.channels.ClosedChannelException; import java.time.Duration; import java.util.Queue; @@ -373,7 +373,7 @@ private void releaseFramesToPosition(long remoteImpliedPos) { } static boolean isResumableFrame(ByteBuf frame) { - switch (FrameHeaderFlyweight.nativeFrameType(frame)) { + switch (FrameHeaderCodec.nativeFrameType(frame)) { case REQUEST_CHANNEL: case REQUEST_STREAM: case REQUEST_RESPONSE: diff --git a/rsocket-core/src/main/java/io/rsocket/resume/ServerRSocketSession.java b/rsocket-core/src/main/java/io/rsocket/resume/ServerRSocketSession.java index 5d55559cc..b54ce644f 100644 --- a/rsocket-core/src/main/java/io/rsocket/resume/ServerRSocketSession.java +++ b/rsocket-core/src/main/java/io/rsocket/resume/ServerRSocketSession.java @@ -20,9 +20,9 @@ import io.netty.buffer.ByteBufAllocator; import io.rsocket.DuplexConnection; import io.rsocket.exceptions.RejectedResumeException; -import io.rsocket.frame.ErrorFrameFlyweight; -import io.rsocket.frame.ResumeFrameFlyweight; -import io.rsocket.frame.ResumeOkFrameFlyweight; +import io.rsocket.frame.ErrorFrameCodec; +import io.rsocket.frame.ResumeFrameCodec; +import io.rsocket.frame.ResumeOkFrameCodec; import java.time.Duration; import java.util.function.Function; import org.slf4j.Logger; @@ -103,12 +103,10 @@ public ServerRSocketSession resumeWith(ByteBuf resumeFrame) { remotePos, remoteImpliedPos, pos -> - pos.flatMap( - impliedPos -> sendFrame(ResumeOkFrameFlyweight.encode(allocator, impliedPos))) + pos.flatMap(impliedPos -> sendFrame(ResumeOkFrameCodec.encode(allocator, impliedPos))) .onErrorResume( err -> - sendFrame( - ErrorFrameFlyweight.encode(allocator, 0, errorFrameThrowable(err))) + sendFrame(ErrorFrameCodec.encode(allocator, 0, errorFrameThrowable(err))) .then(Mono.fromRunnable(resumableConnection::dispose)) /*Resumption is impossible: no need to return control to ResumableConnection*/ .then(Mono.never()))); @@ -136,11 +134,11 @@ private Mono sendFrame(ByteBuf frame) { } private static long remotePos(ByteBuf resumeFrame) { - return ResumeFrameFlyweight.firstAvailableClientPos(resumeFrame); + return ResumeFrameCodec.firstAvailableClientPos(resumeFrame); } private static long remoteImpliedPos(ByteBuf resumeFrame) { - return ResumeFrameFlyweight.lastReceivedServerPos(resumeFrame); + return ResumeFrameCodec.lastReceivedServerPos(resumeFrame); } private static RejectedResumeException errorFrameThrowable(Throwable err) { diff --git a/rsocket-core/src/test/java/io/rsocket/core/ConnectionSetupPayloadTest.java b/rsocket-core/src/test/java/io/rsocket/core/ConnectionSetupPayloadTest.java index ea3142d25..9d8b8354a 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/ConnectionSetupPayloadTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/ConnectionSetupPayloadTest.java @@ -8,7 +8,7 @@ import io.netty.buffer.Unpooled; import io.rsocket.ConnectionSetupPayload; import io.rsocket.Payload; -import io.rsocket.frame.SetupFrameFlyweight; +import io.rsocket.frame.SetupFrameCodec; import io.rsocket.util.DefaultPayload; import org.junit.jupiter.api.Test; @@ -31,8 +31,8 @@ void testSetupPayloadWithDataMetadata() { assertTrue(setupPayload.willClientHonorLease()); assertEquals(KEEP_ALIVE_INTERVAL, setupPayload.keepAliveInterval()); assertEquals(KEEP_ALIVE_MAX_LIFETIME, setupPayload.keepAliveMaxLifetime()); - assertEquals(METADATA_TYPE, SetupFrameFlyweight.metadataMimeType(frame)); - assertEquals(DATA_TYPE, SetupFrameFlyweight.dataMimeType(frame)); + assertEquals(METADATA_TYPE, SetupFrameCodec.metadataMimeType(frame)); + assertEquals(DATA_TYPE, SetupFrameCodec.dataMimeType(frame)); assertTrue(setupPayload.hasMetadata()); assertNotNull(setupPayload.metadata()); assertEquals(payload.metadata(), setupPayload.metadata()); @@ -77,7 +77,7 @@ void testSetupPayloadWithEmptyMetadata() { } private static ByteBuf encodeSetupFrame(boolean leaseEnabled, Payload setupPayload) { - return SetupFrameFlyweight.encode( + return SetupFrameCodec.encode( ByteBufAllocator.DEFAULT, leaseEnabled, KEEP_ALIVE_INTERVAL, diff --git a/rsocket-core/src/test/java/io/rsocket/core/KeepAliveTest.java b/rsocket-core/src/test/java/io/rsocket/core/KeepAliveTest.java index 7e465db08..b3ded08ec 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/KeepAliveTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/KeepAliveTest.java @@ -26,9 +26,9 @@ import io.rsocket.TestScheduler; import io.rsocket.buffer.LeaksTrackingByteBufAllocator; import io.rsocket.exceptions.ConnectionErrorException; -import io.rsocket.frame.FrameHeaderFlyweight; +import io.rsocket.frame.FrameHeaderCodec; import io.rsocket.frame.FrameType; -import io.rsocket.frame.KeepAliveFrameFlyweight; +import io.rsocket.frame.KeepAliveFrameCodec; import io.rsocket.lease.RequesterLeaseHandler; import io.rsocket.resume.InMemoryResumableFramesStore; import io.rsocket.resume.ResumableDuplexConnection; @@ -115,7 +115,7 @@ void rSocketNotDisposedOnPresentKeepAlives() { .subscribe( n -> connection.addToReceivedBuffer( - KeepAliveFrameFlyweight.encode( + KeepAliveFrameCodec.encode( ByteBufAllocator.DEFAULT, true, 0, Unpooled.EMPTY_BUFFER))); Mono.delay(Duration.ofMillis(2000)).block(); @@ -171,7 +171,7 @@ void requesterRespondsToKeepAlives() { .subscribe( l -> connection.addToReceivedBuffer( - KeepAliveFrameFlyweight.encode( + KeepAliveFrameCodec.encode( ByteBufAllocator.DEFAULT, true, 0, Unpooled.EMPTY_BUFFER))); StepVerifier.create(Flux.from(connection.getSentAsPublisher()).take(1)) @@ -235,15 +235,15 @@ void resumableRSocketsNotDisposedOnMissingKeepAlives() { } private boolean keepAliveFrame(ByteBuf frame) { - return FrameHeaderFlyweight.frameType(frame) == FrameType.KEEPALIVE; + return FrameHeaderCodec.frameType(frame) == FrameType.KEEPALIVE; } private boolean keepAliveFrameWithRespondFlag(ByteBuf frame) { - return keepAliveFrame(frame) && KeepAliveFrameFlyweight.respondFlag(frame); + return keepAliveFrame(frame) && KeepAliveFrameCodec.respondFlag(frame); } private boolean keepAliveFrameWithoutRespondFlag(ByteBuf frame) { - return keepAliveFrame(frame) && !KeepAliveFrameFlyweight.respondFlag(frame); + return keepAliveFrame(frame) && !KeepAliveFrameCodec.respondFlag(frame); } static class RSocketState { diff --git a/rsocket-core/src/test/java/io/rsocket/core/PayloadValidationUtilsTest.java b/rsocket-core/src/test/java/io/rsocket/core/PayloadValidationUtilsTest.java index e91fce848..ed9f1ec4a 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/PayloadValidationUtilsTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/PayloadValidationUtilsTest.java @@ -1,8 +1,8 @@ package io.rsocket.core; import io.rsocket.Payload; -import io.rsocket.frame.FrameHeaderFlyweight; -import io.rsocket.frame.FrameLengthFlyweight; +import io.rsocket.frame.FrameHeaderCodec; +import io.rsocket.frame.FrameLengthCodec; import io.rsocket.util.DefaultPayload; import java.util.concurrent.ThreadLocalRandom; import org.assertj.core.api.Assertions; @@ -14,9 +14,9 @@ class PayloadValidationUtilsTest { void shouldBeValidFrameWithNoFragmentation() { byte[] data = new byte - [FrameLengthFlyweight.FRAME_LENGTH_MASK - - FrameLengthFlyweight.FRAME_LENGTH_SIZE - - FrameHeaderFlyweight.size()]; + [FrameLengthCodec.FRAME_LENGTH_MASK + - FrameLengthCodec.FRAME_LENGTH_SIZE + - FrameHeaderCodec.size()]; ThreadLocalRandom.current().nextBytes(data); final Payload payload = DefaultPayload.create(data); @@ -27,9 +27,9 @@ void shouldBeValidFrameWithNoFragmentation() { void shouldBeInValidFrameWithNoFragmentation() { byte[] data = new byte - [FrameLengthFlyweight.FRAME_LENGTH_MASK - - FrameLengthFlyweight.FRAME_LENGTH_SIZE - - FrameHeaderFlyweight.size() + [FrameLengthCodec.FRAME_LENGTH_MASK + - FrameLengthCodec.FRAME_LENGTH_SIZE + - FrameHeaderCodec.size() + 1]; ThreadLocalRandom.current().nextBytes(data); final Payload payload = DefaultPayload.create(data); @@ -39,13 +39,13 @@ void shouldBeInValidFrameWithNoFragmentation() { @Test void shouldBeValidFrameWithNoFragmentation0() { - byte[] metadata = new byte[FrameLengthFlyweight.FRAME_LENGTH_MASK / 2]; + byte[] metadata = new byte[FrameLengthCodec.FRAME_LENGTH_MASK / 2]; byte[] data = new byte - [FrameLengthFlyweight.FRAME_LENGTH_MASK / 2 - - FrameLengthFlyweight.FRAME_LENGTH_SIZE - - FrameHeaderFlyweight.size() - - FrameHeaderFlyweight.size()]; + [FrameLengthCodec.FRAME_LENGTH_MASK / 2 + - FrameLengthCodec.FRAME_LENGTH_SIZE + - FrameHeaderCodec.size() + - FrameHeaderCodec.size()]; ThreadLocalRandom.current().nextBytes(data); ThreadLocalRandom.current().nextBytes(metadata); final Payload payload = DefaultPayload.create(data, metadata); @@ -55,8 +55,8 @@ void shouldBeValidFrameWithNoFragmentation0() { @Test void shouldBeInValidFrameWithNoFragmentation1() { - byte[] metadata = new byte[FrameLengthFlyweight.FRAME_LENGTH_MASK]; - byte[] data = new byte[FrameLengthFlyweight.FRAME_LENGTH_MASK]; + byte[] metadata = new byte[FrameLengthCodec.FRAME_LENGTH_MASK]; + byte[] data = new byte[FrameLengthCodec.FRAME_LENGTH_MASK]; ThreadLocalRandom.current().nextBytes(metadata); ThreadLocalRandom.current().nextBytes(data); final Payload payload = DefaultPayload.create(data, metadata); @@ -77,8 +77,8 @@ void shouldBeValidFrameWithNoFragmentation2() { @Test void shouldBeValidFrameWithNoFragmentation3() { - byte[] metadata = new byte[FrameLengthFlyweight.FRAME_LENGTH_MASK]; - byte[] data = new byte[FrameLengthFlyweight.FRAME_LENGTH_MASK]; + byte[] metadata = new byte[FrameLengthCodec.FRAME_LENGTH_MASK]; + byte[] data = new byte[FrameLengthCodec.FRAME_LENGTH_MASK]; ThreadLocalRandom.current().nextBytes(metadata); ThreadLocalRandom.current().nextBytes(data); final Payload payload = DefaultPayload.create(data, metadata); diff --git a/rsocket-core/src/test/java/io/rsocket/core/RSocketLeaseTest.java b/rsocket-core/src/test/java/io/rsocket/core/RSocketLeaseTest.java index 04d5fe174..ddfbe4234 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/RSocketLeaseTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/RSocketLeaseTest.java @@ -31,10 +31,10 @@ import io.rsocket.TestScheduler; import io.rsocket.buffer.LeaksTrackingByteBufAllocator; import io.rsocket.exceptions.Exceptions; -import io.rsocket.frame.FrameHeaderFlyweight; +import io.rsocket.frame.FrameHeaderCodec; import io.rsocket.frame.FrameType; -import io.rsocket.frame.LeaseFrameFlyweight; -import io.rsocket.frame.SetupFrameFlyweight; +import io.rsocket.frame.LeaseFrameCodec; +import io.rsocket.frame.SetupFrameCodec; import io.rsocket.frame.decoder.PayloadDecoder; import io.rsocket.internal.ClientServerInputMultiplexer; import io.rsocket.lease.*; @@ -123,7 +123,7 @@ void setUp() { public void serverRSocketFactoryRejectsUnsupportedLease() { Payload payload = DefaultPayload.create(DefaultPayload.EMPTY_BUFFER); ByteBuf setupFrame = - SetupFrameFlyweight.encode( + SetupFrameCodec.encode( ByteBufAllocator.DEFAULT, true, 1000, @@ -141,7 +141,7 @@ public void serverRSocketFactoryRejectsUnsupportedLease() { Collection sent = connection.getSent(); Assertions.assertThat(sent).hasSize(1); ByteBuf error = sent.iterator().next(); - Assertions.assertThat(FrameHeaderFlyweight.frameType(error)).isEqualTo(ERROR); + Assertions.assertThat(FrameHeaderCodec.frameType(error)).isEqualTo(ERROR); Assertions.assertThat(Exceptions.from(0, error).getMessage()) .isEqualTo("lease is not supported"); } @@ -154,8 +154,8 @@ public void clientRSocketFactorySetsLeaseFlag() { Collection sent = clientTransport.testConnection().getSent(); Assertions.assertThat(sent).hasSize(1); ByteBuf setup = sent.iterator().next(); - Assertions.assertThat(FrameHeaderFlyweight.frameType(setup)).isEqualTo(SETUP); - Assertions.assertThat(SetupFrameFlyweight.honorLease(setup)).isTrue(); + Assertions.assertThat(FrameHeaderCodec.frameType(setup)).isEqualTo(SETUP); + Assertions.assertThat(SetupFrameCodec.honorLease(setup)).isTrue(); } @ParameterizedTest @@ -278,13 +278,13 @@ void sendLease() { connection .getSent() .stream() - .filter(f -> FrameHeaderFlyweight.frameType(f) == FrameType.LEASE) + .filter(f -> FrameHeaderCodec.frameType(f) == FrameType.LEASE) .findFirst() .orElseThrow(() -> new IllegalStateException("Lease frame not sent")); - Assertions.assertThat(LeaseFrameFlyweight.ttl(leaseFrame)).isEqualTo(ttl); - Assertions.assertThat(LeaseFrameFlyweight.numRequests(leaseFrame)).isEqualTo(numberOfRequests); - Assertions.assertThat(LeaseFrameFlyweight.metadata(leaseFrame).toString(utf8)) + Assertions.assertThat(LeaseFrameCodec.ttl(leaseFrame)).isEqualTo(ttl); + Assertions.assertThat(LeaseFrameCodec.numRequests(leaseFrame)).isEqualTo(numberOfRequests); + Assertions.assertThat(LeaseFrameCodec.metadata(leaseFrame).toString(utf8)) .isEqualTo(metadataContent); } @@ -312,7 +312,7 @@ void receiveLease() { } ByteBuf leaseFrame(int ttl, int requests, ByteBuf metadata) { - return LeaseFrameFlyweight.encode(byteBufAllocator, ttl, requests, metadata); + return LeaseFrameCodec.encode(byteBufAllocator, ttl, requests, metadata); } static Stream>> interactions() { diff --git a/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterSubscribersTest.java b/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterSubscribersTest.java index 3e7479af3..6f1ecf98b 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterSubscribersTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterSubscribersTest.java @@ -21,9 +21,9 @@ import io.rsocket.RSocket; import io.rsocket.TestScheduler; import io.rsocket.buffer.LeaksTrackingByteBufAllocator; -import io.rsocket.frame.FrameHeaderFlyweight; +import io.rsocket.frame.FrameHeaderCodec; import io.rsocket.frame.FrameType; -import io.rsocket.frame.PayloadFrameFlyweight; +import io.rsocket.frame.PayloadFrameCodec; import io.rsocket.frame.decoder.PayloadDecoder; import io.rsocket.internal.subscriber.AssertSubscriber; import io.rsocket.lease.RequesterLeaseHandler; @@ -87,7 +87,7 @@ void singleSubscriber(Function> interaction) { response.subscribe(assertSubscriberA); response.subscribe(assertSubscriberB); - connection.addToReceivedBuffer(PayloadFrameFlyweight.encodeComplete(connection.alloc(), 1)); + connection.addToReceivedBuffer(PayloadFrameCodec.encodeComplete(connection.alloc(), 1)); assertSubscriberA.assertTerminated(); assertSubscriberB.assertTerminated(); @@ -106,7 +106,7 @@ void singleSubscriberInCaseOfRacing(Function> interaction) RaceTestUtils.race( () -> response.subscribe(assertSubscriberA), () -> response.subscribe(assertSubscriberB)); - connection.addToReceivedBuffer(PayloadFrameFlyweight.encodeComplete(connection.alloc(), i)); + connection.addToReceivedBuffer(PayloadFrameCodec.encodeComplete(connection.alloc(), i)); assertSubscriberA.assertTerminated(); assertSubscriberB.assertTerminated(); @@ -117,7 +117,7 @@ void singleSubscriberInCaseOfRacing(Function> interaction) Assertions.assertThat(connection.getSent()) .hasSize(1) .first() - .matches(bb -> REQUEST_TYPES.contains(FrameHeaderFlyweight.frameType(bb))); + .matches(bb -> REQUEST_TYPES.contains(FrameHeaderCodec.frameType(bb))); connection.clearSendReceiveBuffers(); } } @@ -133,7 +133,7 @@ void singleSubscriberInteractionsAreLazy(Function> interac static long requestFramesCount(Collection frames) { return frames .stream() - .filter(frame -> REQUEST_TYPES.contains(FrameHeaderFlyweight.frameType(frame))) + .filter(frame -> REQUEST_TYPES.contains(FrameHeaderCodec.frameType(frame))) .count(); } diff --git a/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterTest.java b/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterTest.java index 56e6c9342..e4943e9b0 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterTest.java @@ -17,7 +17,7 @@ package io.rsocket.core; import static io.rsocket.core.PayloadValidationUtils.INVALID_PAYLOAD_ERROR_MESSAGE; -import static io.rsocket.frame.FrameHeaderFlyweight.frameType; +import static io.rsocket.frame.FrameHeaderCodec.frameType; import static io.rsocket.frame.FrameType.CANCEL; import static io.rsocket.frame.FrameType.REQUEST_CHANNEL; import static io.rsocket.frame.FrameType.REQUEST_FNF; @@ -46,17 +46,17 @@ import io.rsocket.exceptions.ApplicationErrorException; import io.rsocket.exceptions.CustomRSocketException; import io.rsocket.exceptions.RejectedSetupException; -import io.rsocket.frame.CancelFrameFlyweight; -import io.rsocket.frame.ErrorFrameFlyweight; -import io.rsocket.frame.FrameHeaderFlyweight; -import io.rsocket.frame.FrameLengthFlyweight; +import io.rsocket.frame.CancelFrameCodec; +import io.rsocket.frame.ErrorFrameCodec; +import io.rsocket.frame.FrameHeaderCodec; +import io.rsocket.frame.FrameLengthCodec; import io.rsocket.frame.FrameType; -import io.rsocket.frame.PayloadFrameFlyweight; -import io.rsocket.frame.RequestChannelFrameFlyweight; -import io.rsocket.frame.RequestFireAndForgetFrameFlyweight; -import io.rsocket.frame.RequestNFrameFlyweight; -import io.rsocket.frame.RequestResponseFrameFlyweight; -import io.rsocket.frame.RequestStreamFrameFlyweight; +import io.rsocket.frame.PayloadFrameCodec; +import io.rsocket.frame.RequestChannelFrameCodec; +import io.rsocket.frame.RequestFireAndForgetFrameCodec; +import io.rsocket.frame.RequestNFrameCodec; +import io.rsocket.frame.RequestResponseFrameCodec; +import io.rsocket.frame.RequestStreamFrameCodec; import io.rsocket.frame.decoder.PayloadDecoder; import io.rsocket.internal.subscriber.AssertSubscriber; import io.rsocket.lease.RequesterLeaseHandler; @@ -123,7 +123,7 @@ public void tearDown() { @Test @Timeout(2_000) public void testInvalidFrameOnStream0() { - rule.connection.addToReceivedBuffer(RequestNFrameFlyweight.encode(rule.alloc(), 0, 10)); + rule.connection.addToReceivedBuffer(RequestNFrameCodec.encode(rule.alloc(), 0, 10)); assertThat("Unexpected errors.", rule.errors, hasSize(1)); assertThat( "Unexpected error received.", @@ -157,7 +157,7 @@ protected void hookOnSubscribe(Subscription subscription) { ByteBuf f = sent.get(0); assertThat("initial frame", frameType(f), is(REQUEST_STREAM)); - assertThat("initial request n", RequestStreamFrameFlyweight.initialRequestN(f), is(5L)); + assertThat("initial request n", RequestStreamFrameCodec.initialRequestN(f), is(5L)); assertThat("should be released", f.release(), is(true)); rule.assertHasNoLeaks(); } @@ -166,7 +166,7 @@ protected void hookOnSubscribe(Subscription subscription) { @Timeout(2_000) public void testHandleSetupException() { rule.connection.addToReceivedBuffer( - ErrorFrameFlyweight.encode(rule.alloc(), 0, new RejectedSetupException("boom"))); + ErrorFrameCodec.encode(rule.alloc(), 0, new RejectedSetupException("boom"))); assertThat("Unexpected errors.", rule.errors, hasSize(1)); assertThat( "Unexpected error received.", @@ -185,7 +185,7 @@ public void testHandleApplicationException() { int streamId = rule.getStreamIdForRequestType(REQUEST_RESPONSE); rule.connection.addToReceivedBuffer( - ErrorFrameFlyweight.encode(rule.alloc(), streamId, new ApplicationErrorException("error"))); + ErrorFrameCodec.encode(rule.alloc(), streamId, new ApplicationErrorException("error"))); verify(responseSub).onError(any(ApplicationErrorException.class)); @@ -206,7 +206,7 @@ public void testHandleValidFrame() { int streamId = rule.getStreamIdForRequestType(REQUEST_RESPONSE); rule.connection.addToReceivedBuffer( - PayloadFrameFlyweight.encodeNextReleasingPayload( + PayloadFrameCodec.encodeNextReleasingPayload( rule.alloc(), streamId, EmptyPayload.INSTANCE)); verify(sub).onComplete(); @@ -288,9 +288,8 @@ public void testChannelRequestServerSideCancellation() { request.onNext(EmptyPayload.INSTANCE); rule.socket.requestChannel(request).subscribe(cancelled); int streamId = rule.getStreamIdForRequestType(REQUEST_CHANNEL); - rule.connection.addToReceivedBuffer(CancelFrameFlyweight.encode(rule.alloc(), streamId)); - rule.connection.addToReceivedBuffer( - PayloadFrameFlyweight.encodeComplete(rule.alloc(), streamId)); + rule.connection.addToReceivedBuffer(CancelFrameCodec.encode(rule.alloc(), streamId)); + rule.connection.addToReceivedBuffer(PayloadFrameCodec.encodeComplete(rule.alloc(), streamId)); Flux.first( cancelled, Flux.error(new IllegalStateException("Channel request not cancelled")) @@ -328,11 +327,10 @@ protected void hookOnSubscribe(Subscription subscription) {} ByteBuf initialFrame = iterator.next(); - Assertions.assertThat(FrameHeaderFlyweight.frameType(initialFrame)).isEqualTo(REQUEST_CHANNEL); - Assertions.assertThat(RequestChannelFrameFlyweight.initialRequestN(initialFrame)) + Assertions.assertThat(FrameHeaderCodec.frameType(initialFrame)).isEqualTo(REQUEST_CHANNEL); + Assertions.assertThat(RequestChannelFrameCodec.initialRequestN(initialFrame)) .isEqualTo(Long.MAX_VALUE); - Assertions.assertThat( - RequestChannelFrameFlyweight.data(initialFrame).toString(CharsetUtil.UTF_8)) + Assertions.assertThat(RequestChannelFrameCodec.data(initialFrame).toString(CharsetUtil.UTF_8)) .isEqualTo("0"); Assertions.assertThat(initialFrame.release()).isTrue(); @@ -345,8 +343,8 @@ public void shouldThrownExceptionIfGivenPayloadIsExitsSizeAllowanceWithNoFragmen prepareCalls() .forEach( generator -> { - byte[] metadata = new byte[FrameLengthFlyweight.FRAME_LENGTH_MASK]; - byte[] data = new byte[FrameLengthFlyweight.FRAME_LENGTH_MASK]; + byte[] metadata = new byte[FrameLengthCodec.FRAME_LENGTH_MASK]; + byte[] data = new byte[FrameLengthCodec.FRAME_LENGTH_MASK]; ThreadLocalRandom.current().nextBytes(metadata); ThreadLocalRandom.current().nextBytes(data); StepVerifier.create( @@ -374,8 +372,8 @@ static Stream>> prepareCalls() { @Test public void shouldThrownExceptionIfGivenPayloadIsExitsSizeAllowanceWithNoFragmentationForRequestChannelCase() { - byte[] metadata = new byte[FrameLengthFlyweight.FRAME_LENGTH_MASK]; - byte[] data = new byte[FrameLengthFlyweight.FRAME_LENGTH_MASK]; + byte[] metadata = new byte[FrameLengthCodec.FRAME_LENGTH_MASK]; + byte[] data = new byte[FrameLengthCodec.FRAME_LENGTH_MASK]; ThreadLocalRandom.current().nextBytes(metadata); ThreadLocalRandom.current().nextBytes(data); StepVerifier.create( @@ -385,7 +383,7 @@ static Stream>> prepareCalls() { .then( () -> rule.connection.addToReceivedBuffer( - RequestNFrameFlyweight.encode( + RequestNFrameCodec.encode( rule.alloc(), rule.getStreamIdForRequestType(REQUEST_CHANNEL), 2))) .expectErrorSatisfies( t -> @@ -454,7 +452,7 @@ private static Stream racingCases() { as.request(1); int streamId = rule.getStreamIdForRequestType(REQUEST_STREAM); ByteBuf frame = - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, streamId, false, false, true, metadata, data); RaceTestUtils.race(as::cancel, () -> rule.connection.addToReceivedBuffer(frame)); @@ -472,7 +470,7 @@ private static Stream racingCases() { as.request(1); int streamId = rule.getStreamIdForRequestType(REQUEST_CHANNEL); ByteBuf frame = - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, streamId, false, false, true, metadata, data); RaceTestUtils.race(as::cancel, () -> rule.connection.addToReceivedBuffer(frame)); @@ -582,7 +580,7 @@ private static Stream racingCases() { ByteBufAllocator allocator = rule.alloc(); as.request(1); int streamId = rule.getStreamIdForRequestType(REQUEST_CHANNEL); - ByteBuf frame = CancelFrameFlyweight.encode(allocator, streamId); + ByteBuf frame = CancelFrameCodec.encode(allocator, streamId); RaceTestUtils.race( () -> as.request(Long.MAX_VALUE), @@ -609,7 +607,7 @@ private static Stream racingCases() { as.request(1); int streamId = rule.getStreamIdForRequestType(REQUEST_CHANNEL); ByteBuf frame = - ErrorFrameFlyweight.encode(allocator, streamId, new RuntimeException("test")); + ErrorFrameCodec.encode(allocator, streamId, new RuntimeException("test")); RaceTestUtils.race( () -> as.request(Long.MAX_VALUE), @@ -628,7 +626,7 @@ private static Stream racingCases() { as.request(Long.MAX_VALUE); int streamId = rule.getStreamIdForRequestType(REQUEST_RESPONSE); ByteBuf frame = - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, streamId, false, false, true, metadata, data); RaceTestUtils.race(as::cancel, () -> rule.connection.addToReceivedBuffer(frame)); @@ -672,7 +670,7 @@ public void simpleOnDiscardRequestChannelTest2() { testPublisher.next(ByteBufPayload.create("d1", "m1"), ByteBufPayload.create("d2", "m2")); rule.connection.addToReceivedBuffer( - ErrorFrameFlyweight.encode( + ErrorFrameCodec.encode( allocator, streamId, new CustomRSocketException(0x00000404, "test"))); Assertions.assertThat(rule.connection.getSent()).allMatch(ByteBuf::release); @@ -716,7 +714,7 @@ public void verifiesThatFrameWithNoMetadataHasDecodedCorrectlyIntoPayload( if (responsesCnt > 0) { for (int i = 0; i < responsesCnt - 1; i++) { rule.connection.addToReceivedBuffer( - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, streamId, false, @@ -727,7 +725,7 @@ public void verifiesThatFrameWithNoMetadataHasDecodedCorrectlyIntoPayload( } rule.connection.addToReceivedBuffer( - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, streamId, false, @@ -739,7 +737,7 @@ public void verifiesThatFrameWithNoMetadataHasDecodedCorrectlyIntoPayload( if (framesCnt > 1) { rule.connection.addToReceivedBuffer( - RequestNFrameFlyweight.encode(allocator, streamId, framesCnt)); + RequestNFrameCodec.encode(allocator, streamId, framesCnt)); } for (int i = 1; i < framesCnt; i++) { @@ -750,7 +748,7 @@ public void verifiesThatFrameWithNoMetadataHasDecodedCorrectlyIntoPayload( .describedAs( "Interaction Type :[%s]. Expected to observe %s frames sent", frameType, framesCnt) .hasSize(framesCnt) - .allMatch(bb -> !FrameHeaderFlyweight.hasMetadata(bb)) + .allMatch(bb -> !FrameHeaderCodec.hasMetadata(bb)) .allMatch(ByteBuf::release); Assertions.assertThat(assertSubscriber.isTerminated()) @@ -818,12 +816,12 @@ public void ensuresThatNoOpsMustHappenUntilSubscriptionInCaseOfFnfCall() { .hasSize(1) .first() .matches(bb -> frameType(bb) == REQUEST_FNF) - .matches(bb -> FrameHeaderFlyweight.streamId(bb) == 1) + .matches(bb -> FrameHeaderCodec.streamId(bb) == 1) // ensures that this is fnf1 with abc2 data .matches( bb -> ByteBufUtil.equals( - RequestFireAndForgetFrameFlyweight.data(bb), + RequestFireAndForgetFrameCodec.data(bb), Unpooled.wrappedBuffer("abc2".getBytes()))) .matches(ReferenceCounted::release); @@ -836,12 +834,12 @@ public void ensuresThatNoOpsMustHappenUntilSubscriptionInCaseOfFnfCall() { .hasSize(1) .first() .matches(bb -> frameType(bb) == REQUEST_FNF) - .matches(bb -> FrameHeaderFlyweight.streamId(bb) == 3) + .matches(bb -> FrameHeaderCodec.streamId(bb) == 3) // ensures that this is fnf1 with abc1 data .matches( bb -> ByteBufUtil.equals( - RequestFireAndForgetFrameFlyweight.data(bb), + RequestFireAndForgetFrameCodec.data(bb), Unpooled.wrappedBuffer("abc1".getBytes()))) .matches(ReferenceCounted::release); } @@ -875,25 +873,23 @@ public void ensuresThatNoOpsMustHappenUntilFirstRequestN( .first() .matches(bb -> frameType(bb) == frameType) .matches( - bb -> FrameHeaderFlyweight.streamId(bb) == 1, + bb -> FrameHeaderCodec.streamId(bb) == 1, "Expected to have stream ID {1} but got {" - + FrameHeaderFlyweight.streamId(rule.connection.getSent().iterator().next()) + + FrameHeaderCodec.streamId(rule.connection.getSent().iterator().next()) + "}") .matches( bb -> { switch (frameType) { case REQUEST_RESPONSE: return ByteBufUtil.equals( - RequestResponseFrameFlyweight.data(bb), + RequestResponseFrameCodec.data(bb), Unpooled.wrappedBuffer("abc2".getBytes())); case REQUEST_STREAM: return ByteBufUtil.equals( - RequestStreamFrameFlyweight.data(bb), - Unpooled.wrappedBuffer("abc2".getBytes())); + RequestStreamFrameCodec.data(bb), Unpooled.wrappedBuffer("abc2".getBytes())); case REQUEST_CHANNEL: return ByteBufUtil.equals( - RequestChannelFrameFlyweight.data(bb), - Unpooled.wrappedBuffer("abc2".getBytes())); + RequestChannelFrameCodec.data(bb), Unpooled.wrappedBuffer("abc2".getBytes())); } return false; @@ -908,25 +904,23 @@ public void ensuresThatNoOpsMustHappenUntilFirstRequestN( .first() .matches(bb -> frameType(bb) == frameType) .matches( - bb -> FrameHeaderFlyweight.streamId(bb) == 3, + bb -> FrameHeaderCodec.streamId(bb) == 3, "Expected to have stream ID {1} but got {" - + FrameHeaderFlyweight.streamId(rule.connection.getSent().iterator().next()) + + FrameHeaderCodec.streamId(rule.connection.getSent().iterator().next()) + "}") .matches( bb -> { switch (frameType) { case REQUEST_RESPONSE: return ByteBufUtil.equals( - RequestResponseFrameFlyweight.data(bb), + RequestResponseFrameCodec.data(bb), Unpooled.wrappedBuffer("abc1".getBytes())); case REQUEST_STREAM: return ByteBufUtil.equals( - RequestStreamFrameFlyweight.data(bb), - Unpooled.wrappedBuffer("abc1".getBytes())); + RequestStreamFrameCodec.data(bb), Unpooled.wrappedBuffer("abc1".getBytes())); case REQUEST_CHANNEL: return ByteBufUtil.equals( - RequestChannelFrameFlyweight.data(bb), - Unpooled.wrappedBuffer("abc1".getBytes())); + RequestChannelFrameCodec.data(bb), Unpooled.wrappedBuffer("abc1".getBytes())); } return false; @@ -964,7 +958,7 @@ public void ensuresCorrectOrderOfStreamIdIssuingInCaseOfRacing( () -> publisher2.subscribe(AssertSubscriber.create())); Assertions.assertThat(rule.connection.getSent()) - .extracting(FrameHeaderFlyweight::streamId) + .extracting(FrameHeaderCodec::streamId) .containsExactly(i, i + 2); rule.connection.getSent().clear(); } @@ -999,7 +993,7 @@ public int sendRequestResponse(Publisher response) { response.subscribe(sub); int streamId = rule.getStreamIdForRequestType(REQUEST_RESPONSE); rule.connection.addToReceivedBuffer( - PayloadFrameFlyweight.encodeNextCompleteReleasingPayload( + PayloadFrameCodec.encodeNextCompleteReleasingPayload( rule.alloc(), streamId, EmptyPayload.INSTANCE)); verify(sub).onNext(any(Payload.class)); verify(sub).onComplete(); @@ -1028,7 +1022,7 @@ public int getStreamIdForRequestType(FrameType expectedFrameType) { for (ByteBuf frame : connection.getSent()) { FrameType frameType = frameType(frame); if (frameType == expectedFrameType) { - return FrameHeaderFlyweight.streamId(frame); + return FrameHeaderCodec.streamId(frame); } framesFound.add(frameType); } diff --git a/rsocket-core/src/test/java/io/rsocket/core/RSocketResponderTest.java b/rsocket-core/src/test/java/io/rsocket/core/RSocketResponderTest.java index 9ec2a2df1..e34973848 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/RSocketResponderTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/RSocketResponderTest.java @@ -17,7 +17,7 @@ package io.rsocket.core; import static io.rsocket.core.PayloadValidationUtils.INVALID_PAYLOAD_ERROR_MESSAGE; -import static io.rsocket.frame.FrameHeaderFlyweight.frameType; +import static io.rsocket.frame.FrameHeaderCodec.frameType; import static io.rsocket.frame.FrameType.ERROR; import static io.rsocket.frame.FrameType.REQUEST_CHANNEL; import static io.rsocket.frame.FrameType.REQUEST_FNF; @@ -38,18 +38,18 @@ import io.netty.util.ReferenceCounted; import io.rsocket.Payload; import io.rsocket.RSocket; -import io.rsocket.frame.CancelFrameFlyweight; -import io.rsocket.frame.ErrorFrameFlyweight; -import io.rsocket.frame.FrameHeaderFlyweight; -import io.rsocket.frame.FrameLengthFlyweight; +import io.rsocket.frame.CancelFrameCodec; +import io.rsocket.frame.ErrorFrameCodec; +import io.rsocket.frame.FrameHeaderCodec; +import io.rsocket.frame.FrameLengthCodec; import io.rsocket.frame.FrameType; -import io.rsocket.frame.KeepAliveFrameFlyweight; -import io.rsocket.frame.PayloadFrameFlyweight; -import io.rsocket.frame.RequestChannelFrameFlyweight; -import io.rsocket.frame.RequestFireAndForgetFrameFlyweight; -import io.rsocket.frame.RequestNFrameFlyweight; -import io.rsocket.frame.RequestResponseFrameFlyweight; -import io.rsocket.frame.RequestStreamFrameFlyweight; +import io.rsocket.frame.KeepAliveFrameCodec; +import io.rsocket.frame.PayloadFrameCodec; +import io.rsocket.frame.RequestChannelFrameCodec; +import io.rsocket.frame.RequestFireAndForgetFrameCodec; +import io.rsocket.frame.RequestNFrameCodec; +import io.rsocket.frame.RequestResponseFrameCodec; +import io.rsocket.frame.RequestStreamFrameCodec; import io.rsocket.frame.decoder.PayloadDecoder; import io.rsocket.internal.subscriber.AssertSubscriber; import io.rsocket.lease.ResponderLeaseHandler; @@ -117,13 +117,13 @@ public void tearDown() { @Disabled public void testHandleKeepAlive() throws Exception { rule.connection.addToReceivedBuffer( - KeepAliveFrameFlyweight.encode(rule.alloc(), true, 0, Unpooled.EMPTY_BUFFER)); + KeepAliveFrameCodec.encode(rule.alloc(), true, 0, Unpooled.EMPTY_BUFFER)); ByteBuf sent = rule.connection.awaitSend(); assertThat("Unexpected frame sent.", frameType(sent), is(FrameType.KEEPALIVE)); /*Keep alive ack must not have respond flag else, it will result in infinite ping-pong of keep alive frames.*/ assertThat( "Unexpected keep-alive frame respond flag.", - KeepAliveFrameFlyweight.respondFlag(sent), + KeepAliveFrameCodec.respondFlag(sent), is(false)); } @@ -176,7 +176,7 @@ public Mono requestResponse(Payload payload) { assertThat("Unexpected error.", rule.errors, is(empty())); assertThat("Unexpected frame sent.", rule.connection.getSent(), is(empty())); - rule.connection.addToReceivedBuffer(CancelFrameFlyweight.encode(allocator, streamId)); + rule.connection.addToReceivedBuffer(CancelFrameCodec.encode(allocator, streamId)); assertThat("Unexpected frame sent.", rule.connection.getSent(), is(empty())); assertThat("Subscription not cancelled.", cancelled.get(), is(true)); @@ -188,8 +188,8 @@ public Mono requestResponse(Payload payload) { public void shouldThrownExceptionIfGivenPayloadIsExitsSizeAllowanceWithNoFragmentation() { final int streamId = 4; final AtomicBoolean cancelled = new AtomicBoolean(); - byte[] metadata = new byte[FrameLengthFlyweight.FRAME_LENGTH_MASK]; - byte[] data = new byte[FrameLengthFlyweight.FRAME_LENGTH_MASK]; + byte[] metadata = new byte[FrameLengthCodec.FRAME_LENGTH_MASK]; + byte[] data = new byte[FrameLengthCodec.FRAME_LENGTH_MASK]; ThreadLocalRandom.current().nextBytes(metadata); ThreadLocalRandom.current().nextBytes(data); final Payload payload = DefaultPayload.create(data, metadata); @@ -239,8 +239,8 @@ protected void hookOnSubscribe(Subscription subscription) { Assertions.assertThat(rule.connection.getSent()) .hasSize(1) .first() - .matches(bb -> FrameHeaderFlyweight.frameType(bb) == FrameType.ERROR) - .matches(bb -> ErrorFrameFlyweight.dataUtf8(bb).contains(INVALID_PAYLOAD_ERROR_MESSAGE)) + .matches(bb -> FrameHeaderCodec.frameType(bb) == FrameType.ERROR) + .matches(bb -> ErrorFrameCodec.dataUtf8(bb).contains(INVALID_PAYLOAD_ERROR_MESSAGE)) .matches(ReferenceCounted::release); assertThat("Subscription not cancelled.", cancelled.get(), is(true)); @@ -272,21 +272,21 @@ public Flux requestChannel(Publisher payloads) { ByteBuf data1 = allocator.buffer(); data1.writeCharSequence("def1", CharsetUtil.UTF_8); ByteBuf nextFrame1 = - PayloadFrameFlyweight.encode(allocator, 1, false, false, true, metadata1, data1); + PayloadFrameCodec.encode(allocator, 1, false, false, true, metadata1, data1); ByteBuf metadata2 = allocator.buffer(); metadata2.writeCharSequence("abc2", CharsetUtil.UTF_8); ByteBuf data2 = allocator.buffer(); data2.writeCharSequence("def2", CharsetUtil.UTF_8); ByteBuf nextFrame2 = - PayloadFrameFlyweight.encode(allocator, 1, false, false, true, metadata2, data2); + PayloadFrameCodec.encode(allocator, 1, false, false, true, metadata2, data2); ByteBuf metadata3 = allocator.buffer(); metadata3.writeCharSequence("abc3", CharsetUtil.UTF_8); ByteBuf data3 = allocator.buffer(); data3.writeCharSequence("def3", CharsetUtil.UTF_8); ByteBuf nextFrame3 = - PayloadFrameFlyweight.encode(allocator, 1, false, false, true, metadata3, data3); + PayloadFrameCodec.encode(allocator, 1, false, false, true, metadata3, data3); RaceTestUtils.race( () -> { @@ -325,7 +325,7 @@ public Flux requestChannel(Publisher payloads) { rule.sendRequest(1, REQUEST_CHANNEL); - ByteBuf cancelFrame = CancelFrameFlyweight.encode(allocator, 1); + ByteBuf cancelFrame = CancelFrameCodec.encode(allocator, 1); FluxSink sink = sinks[0]; RaceTestUtils.race( () -> rule.connection.addToReceivedBuffer(cancelFrame), @@ -365,8 +365,8 @@ public Flux requestChannel(Publisher payloads) { rule.sendRequest(1, REQUEST_CHANNEL); - ByteBuf cancelFrame = CancelFrameFlyweight.encode(allocator, 1); - ByteBuf requestNFrame = RequestNFrameFlyweight.encode(allocator, 1, Integer.MAX_VALUE); + ByteBuf cancelFrame = CancelFrameCodec.encode(allocator, 1); + ByteBuf requestNFrame = RequestNFrameCodec.encode(allocator, 1, Integer.MAX_VALUE); FluxSink sink = sinks[0]; RaceTestUtils.race( () -> @@ -418,23 +418,23 @@ public Flux requestChannel(Publisher payloads) { ByteBuf data1 = allocator.buffer(); data1.writeCharSequence("def1", CharsetUtil.UTF_8); ByteBuf nextFrame1 = - PayloadFrameFlyweight.encode(allocator, 1, false, false, true, metadata1, data1); + PayloadFrameCodec.encode(allocator, 1, false, false, true, metadata1, data1); ByteBuf metadata2 = allocator.buffer(); metadata2.writeCharSequence("abc2", CharsetUtil.UTF_8); ByteBuf data2 = allocator.buffer(); data2.writeCharSequence("def2", CharsetUtil.UTF_8); ByteBuf nextFrame2 = - PayloadFrameFlyweight.encode(allocator, 1, false, false, true, metadata2, data2); + PayloadFrameCodec.encode(allocator, 1, false, false, true, metadata2, data2); ByteBuf metadata3 = allocator.buffer(); metadata3.writeCharSequence("abc3", CharsetUtil.UTF_8); ByteBuf data3 = allocator.buffer(); data3.writeCharSequence("def3", CharsetUtil.UTF_8); ByteBuf nextFrame3 = - PayloadFrameFlyweight.encode(allocator, 1, false, false, true, metadata3, data3); + PayloadFrameCodec.encode(allocator, 1, false, false, true, metadata3, data3); - ByteBuf requestNFrame = RequestNFrameFlyweight.encode(allocator, 1, Integer.MAX_VALUE); + ByteBuf requestNFrame = RequestNFrameCodec.encode(allocator, 1, Integer.MAX_VALUE); FluxSink sink = sinks[0]; RaceTestUtils.race( @@ -477,7 +477,7 @@ public Flux requestStream(Payload payload) { rule.sendRequest(1, REQUEST_STREAM); - ByteBuf cancelFrame = CancelFrameFlyweight.encode(allocator, 1); + ByteBuf cancelFrame = CancelFrameCodec.encode(allocator, 1); FluxSink sink = sinks[0]; RaceTestUtils.race( () -> rule.connection.addToReceivedBuffer(cancelFrame), @@ -520,7 +520,7 @@ public void subscribe(CoreSubscriber actual) { rule.sendRequest(1, REQUEST_RESPONSE); - ByteBuf cancelFrame = CancelFrameFlyweight.encode(allocator, 1); + ByteBuf cancelFrame = CancelFrameCodec.encode(allocator, 1); RaceTestUtils.race( () -> rule.connection.addToReceivedBuffer(cancelFrame), () -> { @@ -551,7 +551,7 @@ public Flux requestStream(Payload payload) { rule.sendRequest(1, REQUEST_STREAM); - ByteBuf cancelFrame = CancelFrameFlyweight.encode(allocator, 1); + ByteBuf cancelFrame = CancelFrameCodec.encode(allocator, 1); FluxSink sink = sinks[0]; sink.next(ByteBufPayload.create("d1", "m1")); @@ -579,28 +579,28 @@ public Flux requestChannel(Publisher payloads) { rule.sendRequest(1, REQUEST_STREAM); - ByteBuf cancelFrame = CancelFrameFlyweight.encode(allocator, 1); + ByteBuf cancelFrame = CancelFrameCodec.encode(allocator, 1); ByteBuf metadata1 = allocator.buffer(); metadata1.writeCharSequence("abc1", CharsetUtil.UTF_8); ByteBuf data1 = allocator.buffer(); data1.writeCharSequence("def1", CharsetUtil.UTF_8); ByteBuf nextFrame1 = - PayloadFrameFlyweight.encode(allocator, 1, false, false, true, metadata1, data1); + PayloadFrameCodec.encode(allocator, 1, false, false, true, metadata1, data1); ByteBuf metadata2 = allocator.buffer(); metadata2.writeCharSequence("abc2", CharsetUtil.UTF_8); ByteBuf data2 = allocator.buffer(); data2.writeCharSequence("def2", CharsetUtil.UTF_8); ByteBuf nextFrame2 = - PayloadFrameFlyweight.encode(allocator, 1, false, false, true, metadata2, data2); + PayloadFrameCodec.encode(allocator, 1, false, false, true, metadata2, data2); ByteBuf metadata3 = allocator.buffer(); metadata3.writeCharSequence("abc3", CharsetUtil.UTF_8); ByteBuf data3 = allocator.buffer(); data3.writeCharSequence("de3", CharsetUtil.UTF_8); ByteBuf nextFrame3 = - PayloadFrameFlyweight.encode(allocator, 1, false, false, true, metadata3, data3); + PayloadFrameCodec.encode(allocator, 1, false, false, true, metadata3, data3); rule.connection.addToReceivedBuffer(nextFrame1, nextFrame2, nextFrame3); rule.connection.addToReceivedBuffer(cancelFrame); @@ -651,7 +651,7 @@ public Flux requestChannel(Publisher payloads) { // if responses number is bigger than 1 we have to send one extra requestN if (responsesCnt > 1) { rule.connection.addToReceivedBuffer( - RequestNFrameFlyweight.encode(allocator, 1, responsesCnt - 1)); + RequestNFrameCodec.encode(allocator, 1, responsesCnt - 1)); } // respond with specific number of elements @@ -663,7 +663,7 @@ public Flux requestChannel(Publisher payloads) { if (framesCnt > 1) { for (int i = 1; i < responsesCnt; i++) { rule.connection.addToReceivedBuffer( - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, false, @@ -680,7 +680,7 @@ public Flux requestChannel(Publisher payloads) { .describedAs( "Interaction Type :[%s]. Expected to observe %s frames sent", frameType, responsesCnt) .hasSize(responsesCnt) - .allMatch(bb -> !FrameHeaderFlyweight.hasMetadata(bb)); + .allMatch(bb -> !FrameHeaderCodec.hasMetadata(bb)); } if (framesCnt > 1) { @@ -691,7 +691,7 @@ public Flux requestChannel(Publisher payloads) { frameType, framesCnt - 1) .hasSize(1) .first() - .matches(bb -> RequestNFrameFlyweight.requestN(bb) == (framesCnt - 1)); + .matches(bb -> RequestNFrameCodec.requestN(bb) == (framesCnt - 1)); } Assertions.assertThat(rule.connection.getSent()).allMatch(ReferenceCounted::release); @@ -813,22 +813,20 @@ private void sendRequest(int streamId, FrameType frameType, Payload payload) { switch (frameType) { case REQUEST_CHANNEL: request = - RequestChannelFrameFlyweight.encodeReleasingPayload( + RequestChannelFrameCodec.encodeReleasingPayload( allocator, streamId, false, prefetch, payload); break; case REQUEST_STREAM: request = - RequestStreamFrameFlyweight.encodeReleasingPayload( + RequestStreamFrameCodec.encodeReleasingPayload( allocator, streamId, prefetch, payload); break; case REQUEST_RESPONSE: - request = - RequestResponseFrameFlyweight.encodeReleasingPayload(allocator, streamId, payload); + request = RequestResponseFrameCodec.encodeReleasingPayload(allocator, streamId, payload); break; case REQUEST_FNF: request = - RequestFireAndForgetFrameFlyweight.encodeReleasingPayload( - allocator, streamId, payload); + RequestFireAndForgetFrameCodec.encodeReleasingPayload(allocator, streamId, payload); break; default: throw new IllegalArgumentException("unsupported type: " + frameType); diff --git a/rsocket-core/src/test/java/io/rsocket/core/SetupRejectionTest.java b/rsocket-core/src/test/java/io/rsocket/core/SetupRejectionTest.java index 388bfffeb..75a5e070e 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/SetupRejectionTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/SetupRejectionTest.java @@ -9,10 +9,10 @@ import io.rsocket.buffer.LeaksTrackingByteBufAllocator; import io.rsocket.exceptions.Exceptions; import io.rsocket.exceptions.RejectedSetupException; -import io.rsocket.frame.ErrorFrameFlyweight; -import io.rsocket.frame.FrameHeaderFlyweight; +import io.rsocket.frame.ErrorFrameCodec; +import io.rsocket.frame.FrameHeaderCodec; import io.rsocket.frame.FrameType; -import io.rsocket.frame.SetupFrameFlyweight; +import io.rsocket.frame.SetupFrameCodec; import io.rsocket.lease.RequesterLeaseHandler; import io.rsocket.test.util.TestDuplexConnection; import io.rsocket.transport.ServerTransport; @@ -39,7 +39,7 @@ void responderRejectSetup() { transport.connect(); ByteBuf sentFrame = transport.awaitSent(); - assertThat(FrameHeaderFlyweight.frameType(sentFrame)).isEqualTo(FrameType.ERROR); + assertThat(FrameHeaderCodec.frameType(sentFrame)).isEqualTo(FrameType.ERROR); RuntimeException error = Exceptions.from(0, sentFrame); assertThat(errorMsg).isEqualTo(error.getMessage()); assertThat(error).isInstanceOf(RejectedSetupException.class); @@ -75,7 +75,7 @@ void requesterStreamsTerminatedOnZeroErrorFrame() { .doOnRequest( ignored -> conn.addToReceivedBuffer( - ErrorFrameFlyweight.encode( + ErrorFrameCodec.encode( ByteBufAllocator.DEFAULT, 0, new RejectedSetupException(errorMsg))))) @@ -106,8 +106,7 @@ void requesterNewStreamsTerminatedAfterZeroErrorFrame() { TestScheduler.INSTANCE); conn.addToReceivedBuffer( - ErrorFrameFlyweight.encode( - ByteBufAllocator.DEFAULT, 0, new RejectedSetupException("error"))); + ErrorFrameCodec.encode(ByteBufAllocator.DEFAULT, 0, new RejectedSetupException("error"))); StepVerifier.create( rSocket @@ -158,8 +157,7 @@ public ByteBuf awaitSent() { public void connect() { Payload payload = DefaultPayload.create(DefaultPayload.EMPTY_BUFFER); - ByteBuf setup = - SetupFrameFlyweight.encode(allocator, false, 0, 42, "mdMime", "dMime", payload); + ByteBuf setup = SetupFrameCodec.encode(allocator, false, 0, 42, "mdMime", "dMime", payload); conn.addToReceivedBuffer(setup); } diff --git a/rsocket-core/src/test/java/io/rsocket/exceptions/ExceptionsTest.java b/rsocket-core/src/test/java/io/rsocket/exceptions/ExceptionsTest.java index e646080c7..b3f596a37 100644 --- a/rsocket-core/src/test/java/io/rsocket/exceptions/ExceptionsTest.java +++ b/rsocket-core/src/test/java/io/rsocket/exceptions/ExceptionsTest.java @@ -16,22 +16,22 @@ package io.rsocket.exceptions; -import static io.rsocket.frame.ErrorFrameFlyweight.APPLICATION_ERROR; -import static io.rsocket.frame.ErrorFrameFlyweight.CANCELED; -import static io.rsocket.frame.ErrorFrameFlyweight.CONNECTION_CLOSE; -import static io.rsocket.frame.ErrorFrameFlyweight.CONNECTION_ERROR; -import static io.rsocket.frame.ErrorFrameFlyweight.INVALID; -import static io.rsocket.frame.ErrorFrameFlyweight.INVALID_SETUP; -import static io.rsocket.frame.ErrorFrameFlyweight.REJECTED; -import static io.rsocket.frame.ErrorFrameFlyweight.REJECTED_RESUME; -import static io.rsocket.frame.ErrorFrameFlyweight.REJECTED_SETUP; -import static io.rsocket.frame.ErrorFrameFlyweight.UNSUPPORTED_SETUP; +import static io.rsocket.frame.ErrorFrameCodec.APPLICATION_ERROR; +import static io.rsocket.frame.ErrorFrameCodec.CANCELED; +import static io.rsocket.frame.ErrorFrameCodec.CONNECTION_CLOSE; +import static io.rsocket.frame.ErrorFrameCodec.CONNECTION_ERROR; +import static io.rsocket.frame.ErrorFrameCodec.INVALID; +import static io.rsocket.frame.ErrorFrameCodec.INVALID_SETUP; +import static io.rsocket.frame.ErrorFrameCodec.REJECTED; +import static io.rsocket.frame.ErrorFrameCodec.REJECTED_RESUME; +import static io.rsocket.frame.ErrorFrameCodec.REJECTED_SETUP; +import static io.rsocket.frame.ErrorFrameCodec.UNSUPPORTED_SETUP; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatNullPointerException; import io.netty.buffer.ByteBuf; import io.netty.buffer.UnpooledByteBufAllocator; -import io.rsocket.frame.ErrorFrameFlyweight; +import io.rsocket.frame.ErrorFrameCodec; import java.util.concurrent.ThreadLocalRandom; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -205,9 +205,9 @@ void fromCustomRSocketException() { int randomCode = ThreadLocalRandom.current().nextBoolean() ? ThreadLocalRandom.current() - .nextInt(Integer.MIN_VALUE, ErrorFrameFlyweight.MAX_USER_ALLOWED_ERROR_CODE) + .nextInt(Integer.MIN_VALUE, ErrorFrameCodec.MAX_USER_ALLOWED_ERROR_CODE) : ThreadLocalRandom.current() - .nextInt(ErrorFrameFlyweight.MIN_USER_ALLOWED_ERROR_CODE, Integer.MAX_VALUE); + .nextInt(ErrorFrameCodec.MIN_USER_ALLOWED_ERROR_CODE, Integer.MAX_VALUE); ByteBuf byteBuf = createErrorFrame(0, randomCode, "test-message"); assertThat(Exceptions.from(1, byteBuf)) @@ -229,7 +229,7 @@ void fromWithNullFrame() { } private ByteBuf createErrorFrame(int streamId, int errorCode, String message) { - return ErrorFrameFlyweight.encode( + return ErrorFrameCodec.encode( UnpooledByteBufAllocator.DEFAULT, streamId, new TestRSocketException(errorCode, message)); } } diff --git a/rsocket-core/src/test/java/io/rsocket/fragmentation/FragmentationDuplexConnectionTest.java b/rsocket-core/src/test/java/io/rsocket/fragmentation/FragmentationDuplexConnectionTest.java index 9050eaa90..932df4283 100644 --- a/rsocket-core/src/test/java/io/rsocket/fragmentation/FragmentationDuplexConnectionTest.java +++ b/rsocket-core/src/test/java/io/rsocket/fragmentation/FragmentationDuplexConnectionTest.java @@ -87,7 +87,7 @@ void constructorNullDelegate() { @Test void sendData() { ByteBuf encode = - RequestResponseFrameFlyweight.encode( + RequestResponseFrameCodec.encode( allocator, 1, false, Unpooled.EMPTY_BUFFER, Unpooled.wrappedBuffer(data)); when(delegate.onClose()).thenReturn(Mono.never()); @@ -101,8 +101,8 @@ void sendData() { .expectNextCount(17) .assertNext( byteBuf -> { - Assert.assertEquals(FrameType.NEXT, FrameHeaderFlyweight.frameType(byteBuf)); - Assert.assertFalse(FrameHeaderFlyweight.hasFollows(byteBuf)); + Assert.assertEquals(FrameType.NEXT, FrameHeaderCodec.frameType(byteBuf)); + Assert.assertFalse(FrameHeaderCodec.hasFollows(byteBuf)); }) .verifyComplete(); } diff --git a/rsocket-core/src/test/java/io/rsocket/fragmentation/FragmentationIntegrationTest.java b/rsocket-core/src/test/java/io/rsocket/fragmentation/FragmentationIntegrationTest.java index a8569ef3b..ff62b56f2 100644 --- a/rsocket-core/src/test/java/io/rsocket/fragmentation/FragmentationIntegrationTest.java +++ b/rsocket-core/src/test/java/io/rsocket/fragmentation/FragmentationIntegrationTest.java @@ -2,9 +2,9 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; -import io.rsocket.frame.FrameHeaderFlyweight; +import io.rsocket.frame.FrameHeaderCodec; import io.rsocket.frame.FrameUtil; -import io.rsocket.frame.PayloadFrameFlyweight; +import io.rsocket.frame.PayloadFrameCodec; import io.rsocket.util.DefaultPayload; import java.util.concurrent.ThreadLocalRandom; import org.junit.Assert; @@ -28,7 +28,7 @@ public class FragmentationIntegrationTest { @Test void fragmentAndReassembleData() { ByteBuf frame = - PayloadFrameFlyweight.encodeNextCompleteReleasingPayload( + PayloadFrameCodec.encodeNextCompleteReleasingPayload( allocator, 2, DefaultPayload.create(data)); System.out.println(FrameUtil.toString(frame)); @@ -36,7 +36,7 @@ void fragmentAndReassembleData() { Publisher fragments = FrameFragmenter.fragmentFrame( - allocator, 64, frame, FrameHeaderFlyweight.frameType(frame), false); + allocator, 64, frame, FrameHeaderCodec.frameType(frame), false); FrameReassembler reassembler = new FrameReassembler(allocator); @@ -50,9 +50,8 @@ void fragmentAndReassembleData() { String s = FrameUtil.toString(assembled); System.out.println(s); - Assert.assertEquals( - FrameHeaderFlyweight.frameType(frame), FrameHeaderFlyweight.frameType(assembled)); + Assert.assertEquals(FrameHeaderCodec.frameType(frame), FrameHeaderCodec.frameType(assembled)); Assert.assertEquals(frame.readableBytes(), assembled.readableBytes()); - Assert.assertEquals(PayloadFrameFlyweight.data(frame), PayloadFrameFlyweight.data(assembled)); + Assert.assertEquals(PayloadFrameCodec.data(frame), PayloadFrameCodec.data(assembled)); } } diff --git a/rsocket-core/src/test/java/io/rsocket/fragmentation/FrameFragmenterTest.java b/rsocket-core/src/test/java/io/rsocket/fragmentation/FrameFragmenterTest.java index c6b1735e6..60dbef74b 100644 --- a/rsocket-core/src/test/java/io/rsocket/fragmentation/FrameFragmenterTest.java +++ b/rsocket-core/src/test/java/io/rsocket/fragmentation/FrameFragmenterTest.java @@ -42,16 +42,14 @@ final class FrameFragmenterTest { @Test void testGettingData() { ByteBuf rr = - RequestResponseFrameFlyweight.encode( - allocator, 1, true, null, Unpooled.wrappedBuffer(data)); + RequestResponseFrameCodec.encode(allocator, 1, true, null, Unpooled.wrappedBuffer(data)); ByteBuf fnf = - RequestFireAndForgetFrameFlyweight.encode( + RequestFireAndForgetFrameCodec.encode( allocator, 1, true, null, Unpooled.wrappedBuffer(data)); ByteBuf rs = - RequestStreamFrameFlyweight.encode( - allocator, 1, true, 1, null, Unpooled.wrappedBuffer(data)); + RequestStreamFrameCodec.encode(allocator, 1, true, 1, null, Unpooled.wrappedBuffer(data)); ByteBuf rc = - RequestChannelFrameFlyweight.encode( + RequestChannelFrameCodec.encode( allocator, 1, true, false, 1, null, Unpooled.wrappedBuffer(data)); ByteBuf data = FrameFragmenter.getData(rr, FrameType.REQUEST_RESPONSE); @@ -74,16 +72,16 @@ void testGettingData() { @Test void testGettingMetadata() { ByteBuf rr = - RequestResponseFrameFlyweight.encode( + RequestResponseFrameCodec.encode( allocator, 1, true, Unpooled.wrappedBuffer(metadata), Unpooled.wrappedBuffer(data)); ByteBuf fnf = - RequestFireAndForgetFrameFlyweight.encode( + RequestFireAndForgetFrameCodec.encode( allocator, 1, true, Unpooled.wrappedBuffer(metadata), Unpooled.wrappedBuffer(data)); ByteBuf rs = - RequestStreamFrameFlyweight.encode( + RequestStreamFrameCodec.encode( allocator, 1, true, 1, Unpooled.wrappedBuffer(metadata), Unpooled.wrappedBuffer(data)); ByteBuf rc = - RequestChannelFrameFlyweight.encode( + RequestChannelFrameCodec.encode( allocator, 1, true, @@ -112,8 +110,7 @@ void testGettingMetadata() { @Test void returnEmptBufferWhenNoMetadataPresent() { ByteBuf rr = - RequestResponseFrameFlyweight.encode( - allocator, 1, true, null, Unpooled.wrappedBuffer(data)); + RequestResponseFrameCodec.encode(allocator, 1, true, null, Unpooled.wrappedBuffer(data)); ByteBuf data = FrameFragmenter.getMetadata(rr, FrameType.REQUEST_RESPONSE); Assert.assertEquals(data, Unpooled.EMPTY_BUFFER); @@ -124,8 +121,7 @@ void returnEmptBufferWhenNoMetadataPresent() { @Test void encodeFirstFrameWithData() { ByteBuf rr = - RequestResponseFrameFlyweight.encode( - allocator, 1, true, null, Unpooled.wrappedBuffer(data)); + RequestResponseFrameCodec.encode(allocator, 1, true, null, Unpooled.wrappedBuffer(data)); ByteBuf fragment = FrameFragmenter.encodeFirstFragment( @@ -138,22 +134,22 @@ void encodeFirstFrameWithData() { Unpooled.wrappedBuffer(data)); Assert.assertEquals(256, fragment.readableBytes()); - Assert.assertEquals(FrameType.REQUEST_RESPONSE, FrameHeaderFlyweight.frameType(fragment)); - Assert.assertEquals(1, FrameHeaderFlyweight.streamId(fragment)); - Assert.assertTrue(FrameHeaderFlyweight.hasFollows(fragment)); + Assert.assertEquals(FrameType.REQUEST_RESPONSE, FrameHeaderCodec.frameType(fragment)); + Assert.assertEquals(1, FrameHeaderCodec.streamId(fragment)); + Assert.assertTrue(FrameHeaderCodec.hasFollows(fragment)); - ByteBuf data = RequestResponseFrameFlyweight.data(fragment); + ByteBuf data = RequestResponseFrameCodec.data(fragment); ByteBuf byteBuf = Unpooled.wrappedBuffer(this.data).readSlice(data.readableBytes()); Assert.assertEquals(byteBuf, data); - Assert.assertFalse(FrameHeaderFlyweight.hasMetadata(fragment)); + Assert.assertFalse(FrameHeaderCodec.hasMetadata(fragment)); } @DisplayName("encode first channel frame") @Test void encodeFirstWithDataChannel() { ByteBuf rc = - RequestChannelFrameFlyweight.encode( + RequestChannelFrameCodec.encode( allocator, 1, true, false, 10, null, Unpooled.wrappedBuffer(data)); ByteBuf fragment = @@ -167,24 +163,23 @@ void encodeFirstWithDataChannel() { Unpooled.wrappedBuffer(data)); Assert.assertEquals(256, fragment.readableBytes()); - Assert.assertEquals(FrameType.REQUEST_CHANNEL, FrameHeaderFlyweight.frameType(fragment)); - Assert.assertEquals(1, FrameHeaderFlyweight.streamId(fragment)); - Assert.assertEquals(10, RequestChannelFrameFlyweight.initialRequestN(fragment)); - Assert.assertTrue(FrameHeaderFlyweight.hasFollows(fragment)); + Assert.assertEquals(FrameType.REQUEST_CHANNEL, FrameHeaderCodec.frameType(fragment)); + Assert.assertEquals(1, FrameHeaderCodec.streamId(fragment)); + Assert.assertEquals(10, RequestChannelFrameCodec.initialRequestN(fragment)); + Assert.assertTrue(FrameHeaderCodec.hasFollows(fragment)); - ByteBuf data = RequestChannelFrameFlyweight.data(fragment); + ByteBuf data = RequestChannelFrameCodec.data(fragment); ByteBuf byteBuf = Unpooled.wrappedBuffer(this.data).readSlice(data.readableBytes()); Assert.assertEquals(byteBuf, data); - Assert.assertFalse(FrameHeaderFlyweight.hasMetadata(fragment)); + Assert.assertFalse(FrameHeaderCodec.hasMetadata(fragment)); } @DisplayName("encode first stream frame") @Test void encodeFirstWithDataStream() { ByteBuf rc = - RequestStreamFrameFlyweight.encode( - allocator, 1, true, 50, null, Unpooled.wrappedBuffer(data)); + RequestStreamFrameCodec.encode(allocator, 1, true, 50, null, Unpooled.wrappedBuffer(data)); ByteBuf fragment = FrameFragmenter.encodeFirstFragment( @@ -197,23 +192,23 @@ void encodeFirstWithDataStream() { Unpooled.wrappedBuffer(data)); Assert.assertEquals(256, fragment.readableBytes()); - Assert.assertEquals(FrameType.REQUEST_STREAM, FrameHeaderFlyweight.frameType(fragment)); - Assert.assertEquals(1, FrameHeaderFlyweight.streamId(fragment)); - Assert.assertEquals(50, RequestStreamFrameFlyweight.initialRequestN(fragment)); - Assert.assertTrue(FrameHeaderFlyweight.hasFollows(fragment)); + Assert.assertEquals(FrameType.REQUEST_STREAM, FrameHeaderCodec.frameType(fragment)); + Assert.assertEquals(1, FrameHeaderCodec.streamId(fragment)); + Assert.assertEquals(50, RequestStreamFrameCodec.initialRequestN(fragment)); + Assert.assertTrue(FrameHeaderCodec.hasFollows(fragment)); - ByteBuf data = RequestStreamFrameFlyweight.data(fragment); + ByteBuf data = RequestStreamFrameCodec.data(fragment); ByteBuf byteBuf = Unpooled.wrappedBuffer(this.data).readSlice(data.readableBytes()); Assert.assertEquals(byteBuf, data); - Assert.assertFalse(FrameHeaderFlyweight.hasMetadata(fragment)); + Assert.assertFalse(FrameHeaderCodec.hasMetadata(fragment)); } @DisplayName("encode first frame with only metadata") @Test void encodeFirstFrameWithMetadata() { ByteBuf rr = - RequestResponseFrameFlyweight.encode( + RequestResponseFrameCodec.encode( allocator, 1, true, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER); ByteBuf fragment = @@ -227,21 +222,21 @@ void encodeFirstFrameWithMetadata() { Unpooled.EMPTY_BUFFER); Assert.assertEquals(256, fragment.readableBytes()); - Assert.assertEquals(FrameType.REQUEST_RESPONSE, FrameHeaderFlyweight.frameType(fragment)); - Assert.assertEquals(1, FrameHeaderFlyweight.streamId(fragment)); - Assert.assertTrue(FrameHeaderFlyweight.hasFollows(fragment)); + Assert.assertEquals(FrameType.REQUEST_RESPONSE, FrameHeaderCodec.frameType(fragment)); + Assert.assertEquals(1, FrameHeaderCodec.streamId(fragment)); + Assert.assertTrue(FrameHeaderCodec.hasFollows(fragment)); - ByteBuf data = RequestResponseFrameFlyweight.data(fragment); + ByteBuf data = RequestResponseFrameCodec.data(fragment); Assert.assertEquals(data, Unpooled.EMPTY_BUFFER); - Assert.assertTrue(FrameHeaderFlyweight.hasMetadata(fragment)); + Assert.assertTrue(FrameHeaderCodec.hasMetadata(fragment)); } @DisplayName("encode first stream frame with data and metadata") @Test void encodeFirstWithDataAndMetadataStream() { ByteBuf rc = - RequestStreamFrameFlyweight.encode( + RequestStreamFrameCodec.encode( allocator, 1, true, 50, Unpooled.wrappedBuffer(metadata), Unpooled.wrappedBuffer(data)); ByteBuf fragment = @@ -255,27 +250,26 @@ void encodeFirstWithDataAndMetadataStream() { Unpooled.wrappedBuffer(data)); Assert.assertEquals(256, fragment.readableBytes()); - Assert.assertEquals(FrameType.REQUEST_STREAM, FrameHeaderFlyweight.frameType(fragment)); - Assert.assertEquals(1, FrameHeaderFlyweight.streamId(fragment)); - Assert.assertEquals(50, RequestStreamFrameFlyweight.initialRequestN(fragment)); - Assert.assertTrue(FrameHeaderFlyweight.hasFollows(fragment)); + Assert.assertEquals(FrameType.REQUEST_STREAM, FrameHeaderCodec.frameType(fragment)); + Assert.assertEquals(1, FrameHeaderCodec.streamId(fragment)); + Assert.assertEquals(50, RequestStreamFrameCodec.initialRequestN(fragment)); + Assert.assertTrue(FrameHeaderCodec.hasFollows(fragment)); - ByteBuf data = RequestStreamFrameFlyweight.data(fragment); + ByteBuf data = RequestStreamFrameCodec.data(fragment); Assert.assertEquals(0, data.readableBytes()); - ByteBuf metadata = RequestStreamFrameFlyweight.metadata(fragment); + ByteBuf metadata = RequestStreamFrameCodec.metadata(fragment); ByteBuf byteBuf = Unpooled.wrappedBuffer(this.metadata).readSlice(metadata.readableBytes()); Assert.assertEquals(byteBuf, metadata); - Assert.assertTrue(FrameHeaderFlyweight.hasMetadata(fragment)); + Assert.assertTrue(FrameHeaderCodec.hasMetadata(fragment)); } @DisplayName("fragments frame with only data") @Test void fragmentData() { ByteBuf rr = - RequestResponseFrameFlyweight.encode( - allocator, 1, true, null, Unpooled.wrappedBuffer(data)); + RequestResponseFrameCodec.encode(allocator, 1, true, null, Unpooled.wrappedBuffer(data)); Publisher fragments = FrameFragmenter.fragmentFrame(allocator, 1024, rr, FrameType.REQUEST_RESPONSE, false); @@ -284,15 +278,15 @@ void fragmentData() { .expectNextCount(1) .assertNext( byteBuf -> { - Assert.assertEquals(FrameType.NEXT, FrameHeaderFlyweight.frameType(byteBuf)); - Assert.assertEquals(1, FrameHeaderFlyweight.streamId(byteBuf)); - Assert.assertTrue(FrameHeaderFlyweight.hasFollows(byteBuf)); + Assert.assertEquals(FrameType.NEXT, FrameHeaderCodec.frameType(byteBuf)); + Assert.assertEquals(1, FrameHeaderCodec.streamId(byteBuf)); + Assert.assertTrue(FrameHeaderCodec.hasFollows(byteBuf)); }) .expectNextCount(2) .assertNext( byteBuf -> { - Assert.assertEquals(FrameType.NEXT, FrameHeaderFlyweight.frameType(byteBuf)); - Assert.assertFalse(FrameHeaderFlyweight.hasFollows(byteBuf)); + Assert.assertEquals(FrameType.NEXT, FrameHeaderCodec.frameType(byteBuf)); + Assert.assertFalse(FrameHeaderCodec.hasFollows(byteBuf)); }) .verifyComplete(); } @@ -301,7 +295,7 @@ void fragmentData() { @Test void fragmentMetadata() { ByteBuf rr = - RequestStreamFrameFlyweight.encode( + RequestStreamFrameCodec.encode( allocator, 1, true, 10, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER); Publisher fragments = @@ -311,15 +305,15 @@ void fragmentMetadata() { .expectNextCount(1) .assertNext( byteBuf -> { - Assert.assertEquals(FrameType.NEXT, FrameHeaderFlyweight.frameType(byteBuf)); - Assert.assertEquals(1, FrameHeaderFlyweight.streamId(byteBuf)); - Assert.assertTrue(FrameHeaderFlyweight.hasFollows(byteBuf)); + Assert.assertEquals(FrameType.NEXT, FrameHeaderCodec.frameType(byteBuf)); + Assert.assertEquals(1, FrameHeaderCodec.streamId(byteBuf)); + Assert.assertTrue(FrameHeaderCodec.hasFollows(byteBuf)); }) .expectNextCount(2) .assertNext( byteBuf -> { - Assert.assertEquals(FrameType.NEXT, FrameHeaderFlyweight.frameType(byteBuf)); - Assert.assertFalse(FrameHeaderFlyweight.hasFollows(byteBuf)); + Assert.assertEquals(FrameType.NEXT, FrameHeaderCodec.frameType(byteBuf)); + Assert.assertFalse(FrameHeaderCodec.hasFollows(byteBuf)); }) .verifyComplete(); } @@ -328,7 +322,7 @@ void fragmentMetadata() { @Test void fragmentDataAndMetadata() { ByteBuf rr = - RequestResponseFrameFlyweight.encode( + RequestResponseFrameCodec.encode( allocator, 1, true, Unpooled.wrappedBuffer(metadata), Unpooled.wrappedBuffer(data)); Publisher fragments = @@ -337,20 +331,19 @@ void fragmentDataAndMetadata() { StepVerifier.create(Flux.from(fragments).doOnError(Throwable::printStackTrace)) .assertNext( byteBuf -> { - Assert.assertEquals( - FrameType.REQUEST_RESPONSE, FrameHeaderFlyweight.frameType(byteBuf)); - Assert.assertTrue(FrameHeaderFlyweight.hasFollows(byteBuf)); + Assert.assertEquals(FrameType.REQUEST_RESPONSE, FrameHeaderCodec.frameType(byteBuf)); + Assert.assertTrue(FrameHeaderCodec.hasFollows(byteBuf)); }) .expectNextCount(6) .assertNext( byteBuf -> { - Assert.assertEquals(FrameType.NEXT, FrameHeaderFlyweight.frameType(byteBuf)); - Assert.assertTrue(FrameHeaderFlyweight.hasFollows(byteBuf)); + Assert.assertEquals(FrameType.NEXT, FrameHeaderCodec.frameType(byteBuf)); + Assert.assertTrue(FrameHeaderCodec.hasFollows(byteBuf)); }) .assertNext( byteBuf -> { - Assert.assertEquals(FrameType.NEXT, FrameHeaderFlyweight.frameType(byteBuf)); - Assert.assertFalse(FrameHeaderFlyweight.hasFollows(byteBuf)); + Assert.assertEquals(FrameType.NEXT, FrameHeaderCodec.frameType(byteBuf)); + Assert.assertFalse(FrameHeaderCodec.hasFollows(byteBuf)); }) .verifyComplete(); } diff --git a/rsocket-core/src/test/java/io/rsocket/fragmentation/FrameReassemblerTest.java b/rsocket-core/src/test/java/io/rsocket/fragmentation/FrameReassemblerTest.java index 13632165b..56f7fcf90 100644 --- a/rsocket-core/src/test/java/io/rsocket/fragmentation/FrameReassemblerTest.java +++ b/rsocket-core/src/test/java/io/rsocket/fragmentation/FrameReassemblerTest.java @@ -47,15 +47,15 @@ final class FrameReassemblerTest { void reassembleData() { List byteBufs = Arrays.asList( - RequestResponseFrameFlyweight.encode( + RequestResponseFrameCodec.encode( allocator, 1, true, null, Unpooled.wrappedBuffer(data)), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, false, true, null, Unpooled.wrappedBuffer(data)), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, false, true, null, Unpooled.wrappedBuffer(data)), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, false, true, null, Unpooled.wrappedBuffer(data)), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, false, false, true, null, Unpooled.wrappedBuffer(data))); FrameReassembler reassembler = new FrameReassembler(allocator); @@ -76,7 +76,7 @@ void reassembleData() { StepVerifier.create(assembled) .assertNext( byteBuf -> { - Assert.assertEquals(data, RequestResponseFrameFlyweight.data(byteBuf)); + Assert.assertEquals(data, RequestResponseFrameCodec.data(byteBuf)); ReferenceCountUtil.safeRelease(byteBuf); }) .verifyComplete(); @@ -88,7 +88,7 @@ void reassembleData() { void passthrough() { List byteBufs = Arrays.asList( - RequestResponseFrameFlyweight.encode( + RequestResponseFrameCodec.encode( allocator, 1, false, null, Unpooled.wrappedBuffer(data))); FrameReassembler reassembler = new FrameReassembler(allocator); @@ -103,7 +103,7 @@ void passthrough() { StepVerifier.create(assembled) .assertNext( byteBuf -> { - Assert.assertEquals(data, RequestResponseFrameFlyweight.data(byteBuf)); + Assert.assertEquals(data, RequestResponseFrameCodec.data(byteBuf)); ReferenceCountUtil.safeRelease(byteBuf); }) .verifyComplete(); @@ -115,9 +115,9 @@ void passthrough() { void reassembleMetadata() { List byteBufs = Arrays.asList( - RequestResponseFrameFlyweight.encode( + RequestResponseFrameCodec.encode( allocator, 1, true, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, @@ -125,7 +125,7 @@ void reassembleMetadata() { true, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, @@ -133,7 +133,7 @@ void reassembleMetadata() { true, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, @@ -141,7 +141,7 @@ void reassembleMetadata() { true, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, false, @@ -169,7 +169,7 @@ void reassembleMetadata() { .assertNext( byteBuf -> { System.out.println(byteBuf.readableBytes()); - ByteBuf m = RequestResponseFrameFlyweight.metadata(byteBuf); + ByteBuf m = RequestResponseFrameCodec.metadata(byteBuf); Assert.assertEquals(metadata, m); }) .verifyComplete(); @@ -180,7 +180,7 @@ void reassembleMetadata() { void reassembleMetadataChannel() { List byteBufs = Arrays.asList( - RequestChannelFrameFlyweight.encode( + RequestChannelFrameCodec.encode( allocator, 1, true, @@ -188,7 +188,7 @@ void reassembleMetadataChannel() { 100, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, @@ -196,7 +196,7 @@ void reassembleMetadataChannel() { true, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, @@ -204,7 +204,7 @@ void reassembleMetadataChannel() { true, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, @@ -212,7 +212,7 @@ void reassembleMetadataChannel() { true, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, false, @@ -240,9 +240,9 @@ void reassembleMetadataChannel() { .assertNext( byteBuf -> { System.out.println(byteBuf.readableBytes()); - ByteBuf m = RequestChannelFrameFlyweight.metadata(byteBuf); + ByteBuf m = RequestChannelFrameCodec.metadata(byteBuf); Assert.assertEquals(metadata, m); - Assert.assertEquals(100, RequestChannelFrameFlyweight.initialRequestN(byteBuf)); + Assert.assertEquals(100, RequestChannelFrameCodec.initialRequestN(byteBuf)); ReferenceCountUtil.safeRelease(byteBuf); }) .verifyComplete(); @@ -255,9 +255,9 @@ void reassembleMetadataChannel() { void reassembleMetadataStream() { List byteBufs = Arrays.asList( - RequestStreamFrameFlyweight.encode( + RequestStreamFrameCodec.encode( allocator, 1, true, 250, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, @@ -265,7 +265,7 @@ void reassembleMetadataStream() { true, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, @@ -273,7 +273,7 @@ void reassembleMetadataStream() { true, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, @@ -281,7 +281,7 @@ void reassembleMetadataStream() { true, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, false, @@ -309,9 +309,9 @@ void reassembleMetadataStream() { .assertNext( byteBuf -> { System.out.println(byteBuf.readableBytes()); - ByteBuf m = RequestStreamFrameFlyweight.metadata(byteBuf); + ByteBuf m = RequestStreamFrameCodec.metadata(byteBuf); Assert.assertEquals(metadata, m); - Assert.assertEquals(250, RequestChannelFrameFlyweight.initialRequestN(byteBuf)); + Assert.assertEquals(250, RequestChannelFrameCodec.initialRequestN(byteBuf)); ReferenceCountUtil.safeRelease(byteBuf); }) .verifyComplete(); @@ -325,9 +325,9 @@ void reassembleMetadataAndData() { List byteBufs = Arrays.asList( - RequestResponseFrameFlyweight.encode( + RequestResponseFrameCodec.encode( allocator, 1, true, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, @@ -335,7 +335,7 @@ void reassembleMetadataAndData() { true, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, @@ -343,7 +343,7 @@ void reassembleMetadataAndData() { true, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, @@ -351,7 +351,7 @@ void reassembleMetadataAndData() { true, Unpooled.wrappedBuffer(metadata), Unpooled.wrappedBuffer(data)), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, false, false, true, null, Unpooled.wrappedBuffer(data))); FrameReassembler reassembler = new FrameReassembler(allocator); @@ -379,8 +379,8 @@ void reassembleMetadataAndData() { StepVerifier.create(assembled) .assertNext( byteBuf -> { - Assert.assertEquals(data, RequestResponseFrameFlyweight.data(byteBuf)); - Assert.assertEquals(metadata, RequestResponseFrameFlyweight.metadata(byteBuf)); + Assert.assertEquals(data, RequestResponseFrameCodec.data(byteBuf)); + Assert.assertEquals(metadata, RequestResponseFrameCodec.metadata(byteBuf)); }) .verifyComplete(); ReferenceCountUtil.safeRelease(data); @@ -392,9 +392,9 @@ void reassembleMetadataAndData() { public void cancelBeforeAssembling() { List byteBufs = Arrays.asList( - RequestResponseFrameFlyweight.encode( + RequestResponseFrameCodec.encode( allocator, 1, true, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, @@ -402,7 +402,7 @@ public void cancelBeforeAssembling() { true, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, @@ -410,7 +410,7 @@ public void cancelBeforeAssembling() { true, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, @@ -426,7 +426,7 @@ public void cancelBeforeAssembling() { Assert.assertTrue(reassembler.metadata.containsKey(1)); Assert.assertTrue(reassembler.data.containsKey(1)); - Flux.just(CancelFrameFlyweight.encode(allocator, 1)) + Flux.just(CancelFrameCodec.encode(allocator, 1)) .handle(reassembler::reassembleFrame) .blockLast(); @@ -440,9 +440,9 @@ public void cancelBeforeAssembling() { public void dispose() { List byteBufs = Arrays.asList( - RequestResponseFrameFlyweight.encode( + RequestResponseFrameCodec.encode( allocator, 1, true, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, @@ -450,7 +450,7 @@ public void dispose() { true, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, @@ -458,7 +458,7 @@ public void dispose() { true, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, diff --git a/rsocket-core/src/test/java/io/rsocket/fragmentation/ReassembleDuplexConnectionTest.java b/rsocket-core/src/test/java/io/rsocket/fragmentation/ReassembleDuplexConnectionTest.java index 013e2ebc2..b083d6841 100644 --- a/rsocket-core/src/test/java/io/rsocket/fragmentation/ReassembleDuplexConnectionTest.java +++ b/rsocket-core/src/test/java/io/rsocket/fragmentation/ReassembleDuplexConnectionTest.java @@ -26,11 +26,11 @@ import io.netty.buffer.Unpooled; import io.rsocket.DuplexConnection; import io.rsocket.buffer.LeaksTrackingByteBufAllocator; -import io.rsocket.frame.CancelFrameFlyweight; -import io.rsocket.frame.FrameHeaderFlyweight; +import io.rsocket.frame.CancelFrameCodec; +import io.rsocket.frame.FrameHeaderCodec; import io.rsocket.frame.FrameType; -import io.rsocket.frame.PayloadFrameFlyweight; -import io.rsocket.frame.RequestResponseFrameFlyweight; +import io.rsocket.frame.PayloadFrameCodec; +import io.rsocket.frame.RequestResponseFrameCodec; import java.util.Arrays; import java.util.List; import java.util.concurrent.ThreadLocalRandom; @@ -60,15 +60,15 @@ final class ReassembleDuplexConnectionTest { void reassembleData() { List byteBufs = Arrays.asList( - RequestResponseFrameFlyweight.encode( + RequestResponseFrameCodec.encode( allocator, 1, true, null, Unpooled.wrappedBuffer(data)), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, false, true, null, Unpooled.wrappedBuffer(data)), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, false, true, null, Unpooled.wrappedBuffer(data)), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, false, true, null, Unpooled.wrappedBuffer(data)), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, false, false, true, null, Unpooled.wrappedBuffer(data))); CompositeByteBuf data = @@ -91,7 +91,7 @@ void reassembleData() { .as(StepVerifier::create) .assertNext( byteBuf -> { - Assert.assertEquals(data, RequestResponseFrameFlyweight.data(byteBuf)); + Assert.assertEquals(data, RequestResponseFrameCodec.data(byteBuf)); }) .verifyComplete(); } @@ -101,9 +101,9 @@ void reassembleData() { void reassembleMetadata() { List byteBufs = Arrays.asList( - RequestResponseFrameFlyweight.encode( + RequestResponseFrameCodec.encode( allocator, 1, true, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, @@ -111,7 +111,7 @@ void reassembleMetadata() { true, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, @@ -119,7 +119,7 @@ void reassembleMetadata() { true, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, @@ -127,7 +127,7 @@ void reassembleMetadata() { true, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, false, @@ -157,7 +157,7 @@ void reassembleMetadata() { .assertNext( byteBuf -> { System.out.println(byteBuf.readableBytes()); - ByteBuf m = RequestResponseFrameFlyweight.metadata(byteBuf); + ByteBuf m = RequestResponseFrameCodec.metadata(byteBuf); Assert.assertEquals(metadata, m); }) .verifyComplete(); @@ -168,9 +168,9 @@ void reassembleMetadata() { void reassembleMetadataAndData() { List byteBufs = Arrays.asList( - RequestResponseFrameFlyweight.encode( + RequestResponseFrameCodec.encode( allocator, 1, true, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, @@ -178,7 +178,7 @@ void reassembleMetadataAndData() { true, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, @@ -186,7 +186,7 @@ void reassembleMetadataAndData() { true, Unpooled.wrappedBuffer(metadata), Unpooled.EMPTY_BUFFER), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, true, @@ -194,7 +194,7 @@ void reassembleMetadataAndData() { true, Unpooled.wrappedBuffer(metadata), Unpooled.wrappedBuffer(data)), - PayloadFrameFlyweight.encode( + PayloadFrameCodec.encode( allocator, 1, false, false, true, null, Unpooled.wrappedBuffer(data))); CompositeByteBuf data = @@ -224,8 +224,8 @@ void reassembleMetadataAndData() { .as(StepVerifier::create) .assertNext( byteBuf -> { - Assert.assertEquals(data, RequestResponseFrameFlyweight.data(byteBuf)); - Assert.assertEquals(metadata, RequestResponseFrameFlyweight.metadata(byteBuf)); + Assert.assertEquals(data, RequestResponseFrameCodec.data(byteBuf)); + Assert.assertEquals(metadata, RequestResponseFrameCodec.metadata(byteBuf)); }) .verifyComplete(); } @@ -234,8 +234,7 @@ void reassembleMetadataAndData() { @Test void reassembleNonFragment() { ByteBuf encode = - RequestResponseFrameFlyweight.encode( - allocator, 1, false, null, Unpooled.wrappedBuffer(data)); + RequestResponseFrameCodec.encode(allocator, 1, false, null, Unpooled.wrappedBuffer(data)); when(delegate.receive()).thenReturn(Flux.just(encode)); when(delegate.onClose()).thenReturn(Mono.never()); @@ -247,7 +246,7 @@ void reassembleNonFragment() { .assertNext( byteBuf -> { Assert.assertEquals( - Unpooled.wrappedBuffer(data), RequestResponseFrameFlyweight.data(byteBuf)); + Unpooled.wrappedBuffer(data), RequestResponseFrameCodec.data(byteBuf)); }) .verifyComplete(); } @@ -255,7 +254,7 @@ void reassembleNonFragment() { @DisplayName("does not reassemble non fragmentable frame") @Test void reassembleNonFragmentableFrame() { - ByteBuf encode = CancelFrameFlyweight.encode(allocator, 2); + ByteBuf encode = CancelFrameCodec.encode(allocator, 2); when(delegate.receive()).thenReturn(Flux.just(encode)); when(delegate.onClose()).thenReturn(Mono.never()); @@ -266,7 +265,7 @@ void reassembleNonFragmentableFrame() { .as(StepVerifier::create) .assertNext( byteBuf -> { - Assert.assertEquals(FrameType.CANCEL, FrameHeaderFlyweight.frameType(byteBuf)); + Assert.assertEquals(FrameType.CANCEL, FrameHeaderCodec.frameType(byteBuf)); }) .verifyComplete(); } diff --git a/rsocket-core/src/test/java/io/rsocket/frame/ErrorFrameFlyweightTest.java b/rsocket-core/src/test/java/io/rsocket/frame/ErrorFrameCodecTest.java similarity index 65% rename from rsocket-core/src/test/java/io/rsocket/frame/ErrorFrameFlyweightTest.java rename to rsocket-core/src/test/java/io/rsocket/frame/ErrorFrameCodecTest.java index fa663432c..dc04c1141 100644 --- a/rsocket-core/src/test/java/io/rsocket/frame/ErrorFrameFlyweightTest.java +++ b/rsocket-core/src/test/java/io/rsocket/frame/ErrorFrameCodecTest.java @@ -8,13 +8,13 @@ import io.rsocket.exceptions.ApplicationErrorException; import org.junit.jupiter.api.Test; -class ErrorFrameFlyweightTest { +class ErrorFrameCodecTest { @Test void testEncode() { ByteBuf frame = - ErrorFrameFlyweight.encode(ByteBufAllocator.DEFAULT, 1, new ApplicationErrorException("d")); + ErrorFrameCodec.encode(ByteBufAllocator.DEFAULT, 1, new ApplicationErrorException("d")); - frame = FrameLengthFlyweight.encode(ByteBufAllocator.DEFAULT, frame.readableBytes(), frame); + frame = FrameLengthCodec.encode(ByteBufAllocator.DEFAULT, frame.readableBytes(), frame); assertEquals("00000b000000012c000000020164", ByteBufUtil.hexDump(frame)); frame.release(); } diff --git a/rsocket-core/src/test/java/io/rsocket/frame/ExtensionFrameCodecTest.java b/rsocket-core/src/test/java/io/rsocket/frame/ExtensionFrameCodecTest.java new file mode 100644 index 000000000..28209393e --- /dev/null +++ b/rsocket-core/src/test/java/io/rsocket/frame/ExtensionFrameCodecTest.java @@ -0,0 +1,62 @@ +package io.rsocket.frame; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.Unpooled; +import java.nio.charset.StandardCharsets; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class ExtensionFrameCodecTest { + + @Test + void extensionDataMetadata() { + ByteBuf metadata = bytebuf("md"); + ByteBuf data = bytebuf("d"); + int extendedType = 1; + + ByteBuf extension = + ExtensionFrameCodec.encode(ByteBufAllocator.DEFAULT, 1, extendedType, metadata, data); + + Assertions.assertTrue(FrameHeaderCodec.hasMetadata(extension)); + Assertions.assertEquals(extendedType, ExtensionFrameCodec.extendedType(extension)); + Assertions.assertEquals(metadata, ExtensionFrameCodec.metadata(extension)); + Assertions.assertEquals(data, ExtensionFrameCodec.data(extension)); + extension.release(); + } + + @Test + void extensionData() { + ByteBuf data = bytebuf("d"); + int extendedType = 1; + + ByteBuf extension = + ExtensionFrameCodec.encode(ByteBufAllocator.DEFAULT, 1, extendedType, null, data); + + Assertions.assertFalse(FrameHeaderCodec.hasMetadata(extension)); + Assertions.assertEquals(extendedType, ExtensionFrameCodec.extendedType(extension)); + Assertions.assertNull(ExtensionFrameCodec.metadata(extension)); + Assertions.assertEquals(data, ExtensionFrameCodec.data(extension)); + extension.release(); + } + + @Test + void extensionMetadata() { + ByteBuf metadata = bytebuf("md"); + int extendedType = 1; + + ByteBuf extension = + ExtensionFrameCodec.encode( + ByteBufAllocator.DEFAULT, 1, extendedType, metadata, Unpooled.EMPTY_BUFFER); + + Assertions.assertTrue(FrameHeaderCodec.hasMetadata(extension)); + Assertions.assertEquals(extendedType, ExtensionFrameCodec.extendedType(extension)); + Assertions.assertEquals(metadata, ExtensionFrameCodec.metadata(extension)); + Assertions.assertEquals(0, ExtensionFrameCodec.data(extension).readableBytes()); + extension.release(); + } + + private static ByteBuf bytebuf(String str) { + return Unpooled.copiedBuffer(str, StandardCharsets.UTF_8); + } +} diff --git a/rsocket-core/src/test/java/io/rsocket/frame/ExtensionFrameFlyweightTest.java b/rsocket-core/src/test/java/io/rsocket/frame/ExtensionFrameFlyweightTest.java deleted file mode 100644 index eea72c03e..000000000 --- a/rsocket-core/src/test/java/io/rsocket/frame/ExtensionFrameFlyweightTest.java +++ /dev/null @@ -1,62 +0,0 @@ -package io.rsocket.frame; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.Unpooled; -import java.nio.charset.StandardCharsets; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class ExtensionFrameFlyweightTest { - - @Test - void extensionDataMetadata() { - ByteBuf metadata = bytebuf("md"); - ByteBuf data = bytebuf("d"); - int extendedType = 1; - - ByteBuf extension = - ExtensionFrameFlyweight.encode(ByteBufAllocator.DEFAULT, 1, extendedType, metadata, data); - - Assertions.assertTrue(FrameHeaderFlyweight.hasMetadata(extension)); - Assertions.assertEquals(extendedType, ExtensionFrameFlyweight.extendedType(extension)); - Assertions.assertEquals(metadata, ExtensionFrameFlyweight.metadata(extension)); - Assertions.assertEquals(data, ExtensionFrameFlyweight.data(extension)); - extension.release(); - } - - @Test - void extensionData() { - ByteBuf data = bytebuf("d"); - int extendedType = 1; - - ByteBuf extension = - ExtensionFrameFlyweight.encode(ByteBufAllocator.DEFAULT, 1, extendedType, null, data); - - Assertions.assertFalse(FrameHeaderFlyweight.hasMetadata(extension)); - Assertions.assertEquals(extendedType, ExtensionFrameFlyweight.extendedType(extension)); - Assertions.assertNull(ExtensionFrameFlyweight.metadata(extension)); - Assertions.assertEquals(data, ExtensionFrameFlyweight.data(extension)); - extension.release(); - } - - @Test - void extensionMetadata() { - ByteBuf metadata = bytebuf("md"); - int extendedType = 1; - - ByteBuf extension = - ExtensionFrameFlyweight.encode( - ByteBufAllocator.DEFAULT, 1, extendedType, metadata, Unpooled.EMPTY_BUFFER); - - Assertions.assertTrue(FrameHeaderFlyweight.hasMetadata(extension)); - Assertions.assertEquals(extendedType, ExtensionFrameFlyweight.extendedType(extension)); - Assertions.assertEquals(metadata, ExtensionFrameFlyweight.metadata(extension)); - Assertions.assertEquals(0, ExtensionFrameFlyweight.data(extension).readableBytes()); - extension.release(); - } - - private static ByteBuf bytebuf(String str) { - return Unpooled.copiedBuffer(str, StandardCharsets.UTF_8); - } -} diff --git a/rsocket-core/src/test/java/io/rsocket/frame/FrameHeaderFlyweightTest.java b/rsocket-core/src/test/java/io/rsocket/frame/FrameHeaderCodecTest.java similarity index 52% rename from rsocket-core/src/test/java/io/rsocket/frame/FrameHeaderFlyweightTest.java rename to rsocket-core/src/test/java/io/rsocket/frame/FrameHeaderCodecTest.java index a17fcc205..15788e631 100644 --- a/rsocket-core/src/test/java/io/rsocket/frame/FrameHeaderFlyweightTest.java +++ b/rsocket-core/src/test/java/io/rsocket/frame/FrameHeaderCodecTest.java @@ -7,7 +7,7 @@ import io.netty.buffer.ByteBufAllocator; import org.junit.jupiter.api.Test; -class FrameHeaderFlyweightTest { +class FrameHeaderCodecTest { // Taken from spec private static final int FRAME_MAX_SIZE = 16_777_215; @@ -15,10 +15,10 @@ class FrameHeaderFlyweightTest { void typeAndFlag() { FrameType frameType = FrameType.REQUEST_FNF; int flags = 0b1110110111; - ByteBuf header = FrameHeaderFlyweight.encode(ByteBufAllocator.DEFAULT, 0, frameType, flags); + ByteBuf header = FrameHeaderCodec.encode(ByteBufAllocator.DEFAULT, 0, frameType, flags); - assertEquals(flags, FrameHeaderFlyweight.flags(header)); - assertEquals(frameType, FrameHeaderFlyweight.frameType(header)); + assertEquals(flags, FrameHeaderCodec.flags(header)); + assertEquals(frameType, FrameHeaderCodec.frameType(header)); header.release(); } @@ -26,11 +26,11 @@ void typeAndFlag() { void typeAndFlagTruncated() { FrameType frameType = FrameType.SETUP; int flags = 0b11110110111; // 1 bit too many - ByteBuf header = FrameHeaderFlyweight.encode(ByteBufAllocator.DEFAULT, 0, frameType, flags); + ByteBuf header = FrameHeaderCodec.encode(ByteBufAllocator.DEFAULT, 0, frameType, flags); - assertNotEquals(flags, FrameHeaderFlyweight.flags(header)); - assertEquals(flags & 0b0000_0011_1111_1111, FrameHeaderFlyweight.flags(header)); - assertEquals(frameType, FrameHeaderFlyweight.frameType(header)); + assertNotEquals(flags, FrameHeaderCodec.flags(header)); + assertEquals(flags & 0b0000_0011_1111_1111, FrameHeaderCodec.flags(header)); + assertEquals(frameType, FrameHeaderCodec.frameType(header)); header.release(); } } diff --git a/rsocket-core/src/test/java/io/rsocket/frame/RequestFlyweightTest.java b/rsocket-core/src/test/java/io/rsocket/frame/GenericFrameCodecTest.java similarity index 65% rename from rsocket-core/src/test/java/io/rsocket/frame/RequestFlyweightTest.java rename to rsocket-core/src/test/java/io/rsocket/frame/GenericFrameCodecTest.java index c19d4e1f4..ac19dc754 100644 --- a/rsocket-core/src/test/java/io/rsocket/frame/RequestFlyweightTest.java +++ b/rsocket-core/src/test/java/io/rsocket/frame/GenericFrameCodecTest.java @@ -9,11 +9,11 @@ import java.nio.charset.StandardCharsets; import org.junit.jupiter.api.Test; -class RequestFlyweightTest { +class GenericFrameCodecTest { @Test void testEncoding() { ByteBuf frame = - RequestStreamFrameFlyweight.encode( + RequestStreamFrameCodec.encode( ByteBufAllocator.DEFAULT, 1, false, @@ -21,7 +21,7 @@ void testEncoding() { Unpooled.copiedBuffer("md", StandardCharsets.UTF_8), Unpooled.copiedBuffer("d", StandardCharsets.UTF_8)); - frame = FrameLengthFlyweight.encode(ByteBufAllocator.DEFAULT, frame.readableBytes(), frame); + frame = FrameLengthCodec.encode(ByteBufAllocator.DEFAULT, frame.readableBytes(), frame); // Encoded FrameLength⌍ ⌌ Encoded Headers // | | ⌌ Encoded Request(1) // | | | ⌌Encoded Metadata Length @@ -37,7 +37,7 @@ void testEncoding() { @Test void testEncodingWithEmptyMetadata() { ByteBuf frame = - RequestStreamFrameFlyweight.encode( + RequestStreamFrameCodec.encode( ByteBufAllocator.DEFAULT, 1, false, @@ -45,7 +45,7 @@ void testEncodingWithEmptyMetadata() { Unpooled.EMPTY_BUFFER, Unpooled.copiedBuffer("d", StandardCharsets.UTF_8)); - frame = FrameLengthFlyweight.encode(ByteBufAllocator.DEFAULT, frame.readableBytes(), frame); + frame = FrameLengthCodec.encode(ByteBufAllocator.DEFAULT, frame.readableBytes(), frame); // Encoded FrameLength⌍ ⌌ Encoded Headers // | | ⌌ Encoded Request(1) // | | | ⌌Encoded Metadata Length (0) @@ -60,7 +60,7 @@ void testEncodingWithEmptyMetadata() { @Test void testEncodingWithNullMetadata() { ByteBuf frame = - RequestStreamFrameFlyweight.encode( + RequestStreamFrameCodec.encode( ByteBufAllocator.DEFAULT, 1, false, @@ -68,7 +68,7 @@ void testEncodingWithNullMetadata() { null, Unpooled.copiedBuffer("d", StandardCharsets.UTF_8)); - frame = FrameLengthFlyweight.encode(ByteBufAllocator.DEFAULT, frame.readableBytes(), frame); + frame = FrameLengthCodec.encode(ByteBufAllocator.DEFAULT, frame.readableBytes(), frame); // Encoded FrameLength⌍ ⌌ Encoded Headers // | | ⌌ Encoded Request(1) @@ -83,18 +83,17 @@ void testEncodingWithNullMetadata() { @Test void requestResponseDataMetadata() { ByteBuf request = - RequestResponseFrameFlyweight.encode( + RequestResponseFrameCodec.encode( ByteBufAllocator.DEFAULT, 1, false, Unpooled.copiedBuffer("md", StandardCharsets.UTF_8), Unpooled.copiedBuffer("d", StandardCharsets.UTF_8)); - String data = RequestResponseFrameFlyweight.data(request).toString(StandardCharsets.UTF_8); - String metadata = - RequestResponseFrameFlyweight.metadata(request).toString(StandardCharsets.UTF_8); + String data = RequestResponseFrameCodec.data(request).toString(StandardCharsets.UTF_8); + String metadata = RequestResponseFrameCodec.metadata(request).toString(StandardCharsets.UTF_8); - assertTrue(FrameHeaderFlyweight.hasMetadata(request)); + assertTrue(FrameHeaderCodec.hasMetadata(request)); assertEquals("d", data); assertEquals("md", metadata); request.release(); @@ -103,17 +102,17 @@ void requestResponseDataMetadata() { @Test void requestResponseData() { ByteBuf request = - RequestResponseFrameFlyweight.encode( + RequestResponseFrameCodec.encode( ByteBufAllocator.DEFAULT, 1, false, null, Unpooled.copiedBuffer("d", StandardCharsets.UTF_8)); - String data = RequestResponseFrameFlyweight.data(request).toString(StandardCharsets.UTF_8); - ByteBuf metadata = RequestResponseFrameFlyweight.metadata(request); + String data = RequestResponseFrameCodec.data(request).toString(StandardCharsets.UTF_8); + ByteBuf metadata = RequestResponseFrameCodec.metadata(request); - assertFalse(FrameHeaderFlyweight.hasMetadata(request)); + assertFalse(FrameHeaderCodec.hasMetadata(request)); assertEquals("d", data); assertNull(metadata); request.release(); @@ -122,18 +121,17 @@ void requestResponseData() { @Test void requestResponseMetadata() { ByteBuf request = - RequestResponseFrameFlyweight.encode( + RequestResponseFrameCodec.encode( ByteBufAllocator.DEFAULT, 1, false, Unpooled.copiedBuffer("md", StandardCharsets.UTF_8), Unpooled.EMPTY_BUFFER); - ByteBuf data = RequestResponseFrameFlyweight.data(request); - String metadata = - RequestResponseFrameFlyweight.metadata(request).toString(StandardCharsets.UTF_8); + ByteBuf data = RequestResponseFrameCodec.data(request); + String metadata = RequestResponseFrameCodec.metadata(request).toString(StandardCharsets.UTF_8); - assertTrue(FrameHeaderFlyweight.hasMetadata(request)); + assertTrue(FrameHeaderCodec.hasMetadata(request)); assertTrue(data.readableBytes() == 0); assertEquals("md", metadata); request.release(); @@ -142,7 +140,7 @@ void requestResponseMetadata() { @Test void requestStreamDataMetadata() { ByteBuf request = - RequestStreamFrameFlyweight.encode( + RequestStreamFrameCodec.encode( ByteBufAllocator.DEFAULT, 1, false, @@ -150,12 +148,11 @@ void requestStreamDataMetadata() { Unpooled.copiedBuffer("md", StandardCharsets.UTF_8), Unpooled.copiedBuffer("d", StandardCharsets.UTF_8)); - long actualRequest = RequestStreamFrameFlyweight.initialRequestN(request); - String data = RequestStreamFrameFlyweight.data(request).toString(StandardCharsets.UTF_8); - String metadata = - RequestStreamFrameFlyweight.metadata(request).toString(StandardCharsets.UTF_8); + long actualRequest = RequestStreamFrameCodec.initialRequestN(request); + String data = RequestStreamFrameCodec.data(request).toString(StandardCharsets.UTF_8); + String metadata = RequestStreamFrameCodec.metadata(request).toString(StandardCharsets.UTF_8); - assertTrue(FrameHeaderFlyweight.hasMetadata(request)); + assertTrue(FrameHeaderCodec.hasMetadata(request)); assertEquals(Long.MAX_VALUE, actualRequest); assertEquals("md", metadata); assertEquals("d", data); @@ -165,7 +162,7 @@ void requestStreamDataMetadata() { @Test void requestStreamData() { ByteBuf request = - RequestStreamFrameFlyweight.encode( + RequestStreamFrameCodec.encode( ByteBufAllocator.DEFAULT, 1, false, @@ -173,11 +170,11 @@ void requestStreamData() { null, Unpooled.copiedBuffer("d", StandardCharsets.UTF_8)); - long actualRequest = RequestStreamFrameFlyweight.initialRequestN(request); - String data = RequestStreamFrameFlyweight.data(request).toString(StandardCharsets.UTF_8); - ByteBuf metadata = RequestStreamFrameFlyweight.metadata(request); + long actualRequest = RequestStreamFrameCodec.initialRequestN(request); + String data = RequestStreamFrameCodec.data(request).toString(StandardCharsets.UTF_8); + ByteBuf metadata = RequestStreamFrameCodec.metadata(request); - assertFalse(FrameHeaderFlyweight.hasMetadata(request)); + assertFalse(FrameHeaderCodec.hasMetadata(request)); assertEquals(42L, actualRequest); assertNull(metadata); assertEquals("d", data); @@ -187,7 +184,7 @@ void requestStreamData() { @Test void requestStreamMetadata() { ByteBuf request = - RequestStreamFrameFlyweight.encode( + RequestStreamFrameCodec.encode( ByteBufAllocator.DEFAULT, 1, false, @@ -195,12 +192,11 @@ void requestStreamMetadata() { Unpooled.copiedBuffer("md", StandardCharsets.UTF_8), Unpooled.EMPTY_BUFFER); - long actualRequest = RequestStreamFrameFlyweight.initialRequestN(request); - ByteBuf data = RequestStreamFrameFlyweight.data(request); - String metadata = - RequestStreamFrameFlyweight.metadata(request).toString(StandardCharsets.UTF_8); + long actualRequest = RequestStreamFrameCodec.initialRequestN(request); + ByteBuf data = RequestStreamFrameCodec.data(request); + String metadata = RequestStreamFrameCodec.metadata(request).toString(StandardCharsets.UTF_8); - assertTrue(FrameHeaderFlyweight.hasMetadata(request)); + assertTrue(FrameHeaderCodec.hasMetadata(request)); assertEquals(42L, actualRequest); assertTrue(data.readableBytes() == 0); assertEquals("md", metadata); @@ -210,18 +206,18 @@ void requestStreamMetadata() { @Test void requestFnfDataAndMetadata() { ByteBuf request = - RequestFireAndForgetFrameFlyweight.encode( + RequestFireAndForgetFrameCodec.encode( ByteBufAllocator.DEFAULT, 1, false, Unpooled.copiedBuffer("md", StandardCharsets.UTF_8), Unpooled.copiedBuffer("d", StandardCharsets.UTF_8)); - String data = RequestFireAndForgetFrameFlyweight.data(request).toString(StandardCharsets.UTF_8); + String data = RequestFireAndForgetFrameCodec.data(request).toString(StandardCharsets.UTF_8); String metadata = - RequestFireAndForgetFrameFlyweight.metadata(request).toString(StandardCharsets.UTF_8); + RequestFireAndForgetFrameCodec.metadata(request).toString(StandardCharsets.UTF_8); - assertTrue(FrameHeaderFlyweight.hasMetadata(request)); + assertTrue(FrameHeaderCodec.hasMetadata(request)); assertEquals("d", data); assertEquals("md", metadata); request.release(); @@ -230,17 +226,17 @@ void requestFnfDataAndMetadata() { @Test void requestFnfData() { ByteBuf request = - RequestFireAndForgetFrameFlyweight.encode( + RequestFireAndForgetFrameCodec.encode( ByteBufAllocator.DEFAULT, 1, false, null, Unpooled.copiedBuffer("d", StandardCharsets.UTF_8)); - String data = RequestFireAndForgetFrameFlyweight.data(request).toString(StandardCharsets.UTF_8); - ByteBuf metadata = RequestFireAndForgetFrameFlyweight.metadata(request); + String data = RequestFireAndForgetFrameCodec.data(request).toString(StandardCharsets.UTF_8); + ByteBuf metadata = RequestFireAndForgetFrameCodec.metadata(request); - assertFalse(FrameHeaderFlyweight.hasMetadata(request)); + assertFalse(FrameHeaderCodec.hasMetadata(request)); assertEquals("d", data); assertNull(metadata); request.release(); @@ -249,18 +245,18 @@ void requestFnfData() { @Test void requestFnfMetadata() { ByteBuf request = - RequestFireAndForgetFrameFlyweight.encode( + RequestFireAndForgetFrameCodec.encode( ByteBufAllocator.DEFAULT, 1, false, Unpooled.copiedBuffer("md", StandardCharsets.UTF_8), Unpooled.EMPTY_BUFFER); - ByteBuf data = RequestFireAndForgetFrameFlyweight.data(request); + ByteBuf data = RequestFireAndForgetFrameCodec.data(request); String metadata = - RequestFireAndForgetFrameFlyweight.metadata(request).toString(StandardCharsets.UTF_8); + RequestFireAndForgetFrameCodec.metadata(request).toString(StandardCharsets.UTF_8); - assertTrue(FrameHeaderFlyweight.hasMetadata(request)); + assertTrue(FrameHeaderCodec.hasMetadata(request)); assertEquals("md", metadata); assertTrue(data.readableBytes() == 0); request.release(); diff --git a/rsocket-core/src/test/java/io/rsocket/frame/KeepaliveFrameFlyweightTest.java b/rsocket-core/src/test/java/io/rsocket/frame/KeepaliveFrameFlyweightTest.java index eb55e89cd..bc013e024 100644 --- a/rsocket-core/src/test/java/io/rsocket/frame/KeepaliveFrameFlyweightTest.java +++ b/rsocket-core/src/test/java/io/rsocket/frame/KeepaliveFrameFlyweightTest.java @@ -14,18 +14,18 @@ class KeepaliveFrameFlyweightTest { @Test void canReadData() { ByteBuf data = Unpooled.wrappedBuffer(new byte[] {5, 4, 3}); - ByteBuf frame = KeepAliveFrameFlyweight.encode(ByteBufAllocator.DEFAULT, true, 0, data); - assertTrue(KeepAliveFrameFlyweight.respondFlag(frame)); - assertEquals(data, KeepAliveFrameFlyweight.data(frame)); + ByteBuf frame = KeepAliveFrameCodec.encode(ByteBufAllocator.DEFAULT, true, 0, data); + assertTrue(KeepAliveFrameCodec.respondFlag(frame)); + assertEquals(data, KeepAliveFrameCodec.data(frame)); frame.release(); } @Test void testEncoding() { ByteBuf frame = - KeepAliveFrameFlyweight.encode( + KeepAliveFrameCodec.encode( ByteBufAllocator.DEFAULT, true, 0, Unpooled.copiedBuffer("d", StandardCharsets.UTF_8)); - frame = FrameLengthFlyweight.encode(ByteBufAllocator.DEFAULT, frame.readableBytes(), frame); + frame = FrameLengthCodec.encode(ByteBufAllocator.DEFAULT, frame.readableBytes(), frame); assertEquals("00000f000000000c80000000000000000064", ByteBufUtil.hexDump(frame)); frame.release(); } diff --git a/rsocket-core/src/test/java/io/rsocket/frame/LeaseFrameCodecTest.java b/rsocket-core/src/test/java/io/rsocket/frame/LeaseFrameCodecTest.java new file mode 100644 index 000000000..448b5003b --- /dev/null +++ b/rsocket-core/src/test/java/io/rsocket/frame/LeaseFrameCodecTest.java @@ -0,0 +1,42 @@ +package io.rsocket.frame; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.Unpooled; +import java.nio.charset.StandardCharsets; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class LeaseFrameCodecTest { + + @Test + void leaseMetadata() { + ByteBuf metadata = bytebuf("md"); + int ttl = 1; + int numRequests = 42; + ByteBuf lease = LeaseFrameCodec.encode(ByteBufAllocator.DEFAULT, ttl, numRequests, metadata); + + Assertions.assertTrue(FrameHeaderCodec.hasMetadata(lease)); + Assertions.assertEquals(ttl, LeaseFrameCodec.ttl(lease)); + Assertions.assertEquals(numRequests, LeaseFrameCodec.numRequests(lease)); + Assertions.assertEquals(metadata, LeaseFrameCodec.metadata(lease)); + lease.release(); + } + + @Test + void leaseAbsentMetadata() { + int ttl = 1; + int numRequests = 42; + ByteBuf lease = LeaseFrameCodec.encode(ByteBufAllocator.DEFAULT, ttl, numRequests, null); + + Assertions.assertFalse(FrameHeaderCodec.hasMetadata(lease)); + Assertions.assertEquals(ttl, LeaseFrameCodec.ttl(lease)); + Assertions.assertEquals(numRequests, LeaseFrameCodec.numRequests(lease)); + Assertions.assertEquals(0, LeaseFrameCodec.metadata(lease).readableBytes()); + lease.release(); + } + + private static ByteBuf bytebuf(String str) { + return Unpooled.copiedBuffer(str, StandardCharsets.UTF_8); + } +} diff --git a/rsocket-core/src/test/java/io/rsocket/frame/LeaseFrameFlyweightTest.java b/rsocket-core/src/test/java/io/rsocket/frame/LeaseFrameFlyweightTest.java deleted file mode 100644 index 0fc0c112b..000000000 --- a/rsocket-core/src/test/java/io/rsocket/frame/LeaseFrameFlyweightTest.java +++ /dev/null @@ -1,43 +0,0 @@ -package io.rsocket.frame; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.Unpooled; -import java.nio.charset.StandardCharsets; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class LeaseFrameFlyweightTest { - - @Test - void leaseMetadata() { - ByteBuf metadata = bytebuf("md"); - int ttl = 1; - int numRequests = 42; - ByteBuf lease = - LeaseFrameFlyweight.encode(ByteBufAllocator.DEFAULT, ttl, numRequests, metadata); - - Assertions.assertTrue(FrameHeaderFlyweight.hasMetadata(lease)); - Assertions.assertEquals(ttl, LeaseFrameFlyweight.ttl(lease)); - Assertions.assertEquals(numRequests, LeaseFrameFlyweight.numRequests(lease)); - Assertions.assertEquals(metadata, LeaseFrameFlyweight.metadata(lease)); - lease.release(); - } - - @Test - void leaseAbsentMetadata() { - int ttl = 1; - int numRequests = 42; - ByteBuf lease = LeaseFrameFlyweight.encode(ByteBufAllocator.DEFAULT, ttl, numRequests, null); - - Assertions.assertFalse(FrameHeaderFlyweight.hasMetadata(lease)); - Assertions.assertEquals(ttl, LeaseFrameFlyweight.ttl(lease)); - Assertions.assertEquals(numRequests, LeaseFrameFlyweight.numRequests(lease)); - Assertions.assertEquals(0, LeaseFrameFlyweight.metadata(lease).readableBytes()); - lease.release(); - } - - private static ByteBuf bytebuf(String str) { - return Unpooled.copiedBuffer(str, StandardCharsets.UTF_8); - } -} diff --git a/rsocket-core/src/test/java/io/rsocket/frame/PayloadFlyweightTest.java b/rsocket-core/src/test/java/io/rsocket/frame/PayloadFlyweightTest.java index 439d23c15..aecbb31ce 100644 --- a/rsocket-core/src/test/java/io/rsocket/frame/PayloadFlyweightTest.java +++ b/rsocket-core/src/test/java/io/rsocket/frame/PayloadFlyweightTest.java @@ -15,10 +15,9 @@ public class PayloadFlyweightTest { void nextCompleteDataMetadata() { Payload payload = DefaultPayload.create("d", "md"); ByteBuf nextComplete = - PayloadFrameFlyweight.encodeNextCompleteReleasingPayload( - ByteBufAllocator.DEFAULT, 1, payload); - String data = PayloadFrameFlyweight.data(nextComplete).toString(StandardCharsets.UTF_8); - String metadata = PayloadFrameFlyweight.metadata(nextComplete).toString(StandardCharsets.UTF_8); + PayloadFrameCodec.encodeNextCompleteReleasingPayload(ByteBufAllocator.DEFAULT, 1, payload); + String data = PayloadFrameCodec.data(nextComplete).toString(StandardCharsets.UTF_8); + String metadata = PayloadFrameCodec.metadata(nextComplete).toString(StandardCharsets.UTF_8); Assertions.assertEquals("d", data); Assertions.assertEquals("md", metadata); nextComplete.release(); @@ -28,10 +27,9 @@ void nextCompleteDataMetadata() { void nextCompleteData() { Payload payload = DefaultPayload.create("d"); ByteBuf nextComplete = - PayloadFrameFlyweight.encodeNextCompleteReleasingPayload( - ByteBufAllocator.DEFAULT, 1, payload); - String data = PayloadFrameFlyweight.data(nextComplete).toString(StandardCharsets.UTF_8); - ByteBuf metadata = PayloadFrameFlyweight.metadata(nextComplete); + PayloadFrameCodec.encodeNextCompleteReleasingPayload(ByteBufAllocator.DEFAULT, 1, payload); + String data = PayloadFrameCodec.data(nextComplete).toString(StandardCharsets.UTF_8); + ByteBuf metadata = PayloadFrameCodec.metadata(nextComplete); Assertions.assertEquals("d", data); Assertions.assertNull(metadata); nextComplete.release(); @@ -44,10 +42,9 @@ void nextCompleteMetaData() { Unpooled.EMPTY_BUFFER, Unpooled.wrappedBuffer("md".getBytes(StandardCharsets.UTF_8))); ByteBuf nextComplete = - PayloadFrameFlyweight.encodeNextCompleteReleasingPayload( - ByteBufAllocator.DEFAULT, 1, payload); - ByteBuf data = PayloadFrameFlyweight.data(nextComplete); - String metadata = PayloadFrameFlyweight.metadata(nextComplete).toString(StandardCharsets.UTF_8); + PayloadFrameCodec.encodeNextCompleteReleasingPayload(ByteBufAllocator.DEFAULT, 1, payload); + ByteBuf data = PayloadFrameCodec.data(nextComplete); + String metadata = PayloadFrameCodec.metadata(nextComplete).toString(StandardCharsets.UTF_8); Assertions.assertTrue(data.readableBytes() == 0); Assertions.assertEquals("md", metadata); nextComplete.release(); @@ -57,9 +54,9 @@ void nextCompleteMetaData() { void nextDataMetadata() { Payload payload = DefaultPayload.create("d", "md"); ByteBuf next = - PayloadFrameFlyweight.encodeNextReleasingPayload(ByteBufAllocator.DEFAULT, 1, payload); - String data = PayloadFrameFlyweight.data(next).toString(StandardCharsets.UTF_8); - String metadata = PayloadFrameFlyweight.metadata(next).toString(StandardCharsets.UTF_8); + PayloadFrameCodec.encodeNextReleasingPayload(ByteBufAllocator.DEFAULT, 1, payload); + String data = PayloadFrameCodec.data(next).toString(StandardCharsets.UTF_8); + String metadata = PayloadFrameCodec.metadata(next).toString(StandardCharsets.UTF_8); Assertions.assertEquals("d", data); Assertions.assertEquals("md", metadata); next.release(); @@ -69,9 +66,9 @@ void nextDataMetadata() { void nextData() { Payload payload = DefaultPayload.create("d"); ByteBuf next = - PayloadFrameFlyweight.encodeNextReleasingPayload(ByteBufAllocator.DEFAULT, 1, payload); - String data = PayloadFrameFlyweight.data(next).toString(StandardCharsets.UTF_8); - ByteBuf metadata = PayloadFrameFlyweight.metadata(next); + PayloadFrameCodec.encodeNextReleasingPayload(ByteBufAllocator.DEFAULT, 1, payload); + String data = PayloadFrameCodec.data(next).toString(StandardCharsets.UTF_8); + ByteBuf metadata = PayloadFrameCodec.metadata(next); Assertions.assertEquals("d", data); Assertions.assertNull(metadata); next.release(); @@ -81,9 +78,9 @@ void nextData() { void nextDataEmptyMetadata() { Payload payload = DefaultPayload.create("d".getBytes(), new byte[0]); ByteBuf next = - PayloadFrameFlyweight.encodeNextReleasingPayload(ByteBufAllocator.DEFAULT, 1, payload); - String data = PayloadFrameFlyweight.data(next).toString(StandardCharsets.UTF_8); - ByteBuf metadata = PayloadFrameFlyweight.metadata(next); + PayloadFrameCodec.encodeNextReleasingPayload(ByteBufAllocator.DEFAULT, 1, payload); + String data = PayloadFrameCodec.data(next).toString(StandardCharsets.UTF_8); + ByteBuf metadata = PayloadFrameCodec.metadata(next); Assertions.assertEquals("d", data); Assertions.assertEquals(metadata.readableBytes(), 0); next.release(); diff --git a/rsocket-core/src/test/java/io/rsocket/frame/RequestNFrameFlyweightTest.java b/rsocket-core/src/test/java/io/rsocket/frame/RequestNFrameCodecTest.java similarity index 63% rename from rsocket-core/src/test/java/io/rsocket/frame/RequestNFrameFlyweightTest.java rename to rsocket-core/src/test/java/io/rsocket/frame/RequestNFrameCodecTest.java index 4411b98c9..e38258040 100644 --- a/rsocket-core/src/test/java/io/rsocket/frame/RequestNFrameFlyweightTest.java +++ b/rsocket-core/src/test/java/io/rsocket/frame/RequestNFrameCodecTest.java @@ -7,12 +7,12 @@ import io.netty.buffer.ByteBufUtil; import org.junit.jupiter.api.Test; -class RequestNFrameFlyweightTest { +class RequestNFrameCodecTest { @Test void testEncoding() { - ByteBuf frame = RequestNFrameFlyweight.encode(ByteBufAllocator.DEFAULT, 1, 5); + ByteBuf frame = RequestNFrameCodec.encode(ByteBufAllocator.DEFAULT, 1, 5); - frame = FrameLengthFlyweight.encode(ByteBufAllocator.DEFAULT, frame.readableBytes(), frame); + frame = FrameLengthCodec.encode(ByteBufAllocator.DEFAULT, frame.readableBytes(), frame); assertEquals("00000a00000001200000000005", ByteBufUtil.hexDump(frame)); frame.release(); } diff --git a/rsocket-core/src/test/java/io/rsocket/frame/ResumeFrameFlyweightTest.java b/rsocket-core/src/test/java/io/rsocket/frame/ResumeFrameCodecTest.java similarity index 68% rename from rsocket-core/src/test/java/io/rsocket/frame/ResumeFrameFlyweightTest.java rename to rsocket-core/src/test/java/io/rsocket/frame/ResumeFrameCodecTest.java index f8b481f05..fe05335d2 100644 --- a/rsocket-core/src/test/java/io/rsocket/frame/ResumeFrameFlyweightTest.java +++ b/rsocket-core/src/test/java/io/rsocket/frame/ResumeFrameCodecTest.java @@ -23,19 +23,18 @@ import org.junit.Assert; import org.junit.jupiter.api.Test; -public class ResumeFrameFlyweightTest { +public class ResumeFrameCodecTest { @Test void testEncoding() { byte[] tokenBytes = new byte[65000]; Arrays.fill(tokenBytes, (byte) 1); ByteBuf token = Unpooled.wrappedBuffer(tokenBytes); - ByteBuf byteBuf = ResumeFrameFlyweight.encode(ByteBufAllocator.DEFAULT, token, 21, 12); - Assert.assertEquals( - ResumeFrameFlyweight.CURRENT_VERSION, ResumeFrameFlyweight.version(byteBuf)); - Assert.assertEquals(token, ResumeFrameFlyweight.token(byteBuf)); - Assert.assertEquals(21, ResumeFrameFlyweight.lastReceivedServerPos(byteBuf)); - Assert.assertEquals(12, ResumeFrameFlyweight.firstAvailableClientPos(byteBuf)); + ByteBuf byteBuf = ResumeFrameCodec.encode(ByteBufAllocator.DEFAULT, token, 21, 12); + Assert.assertEquals(ResumeFrameCodec.CURRENT_VERSION, ResumeFrameCodec.version(byteBuf)); + Assert.assertEquals(token, ResumeFrameCodec.token(byteBuf)); + Assert.assertEquals(21, ResumeFrameCodec.lastReceivedServerPos(byteBuf)); + Assert.assertEquals(12, ResumeFrameCodec.firstAvailableClientPos(byteBuf)); byteBuf.release(); } } diff --git a/rsocket-core/src/test/java/io/rsocket/frame/ResumeOkFrameFlyweightTest.java b/rsocket-core/src/test/java/io/rsocket/frame/ResumeOkFrameCodecTest.java similarity index 51% rename from rsocket-core/src/test/java/io/rsocket/frame/ResumeOkFrameFlyweightTest.java rename to rsocket-core/src/test/java/io/rsocket/frame/ResumeOkFrameCodecTest.java index c73409ffa..33dd8eb70 100644 --- a/rsocket-core/src/test/java/io/rsocket/frame/ResumeOkFrameFlyweightTest.java +++ b/rsocket-core/src/test/java/io/rsocket/frame/ResumeOkFrameCodecTest.java @@ -5,12 +5,12 @@ import org.junit.Assert; import org.junit.Test; -public class ResumeOkFrameFlyweightTest { +public class ResumeOkFrameCodecTest { @Test public void testEncoding() { - ByteBuf byteBuf = ResumeOkFrameFlyweight.encode(ByteBufAllocator.DEFAULT, 42); - Assert.assertEquals(42, ResumeOkFrameFlyweight.lastReceivedClientPos(byteBuf)); + ByteBuf byteBuf = ResumeOkFrameCodec.encode(ByteBufAllocator.DEFAULT, 42); + Assert.assertEquals(42, ResumeOkFrameCodec.lastReceivedClientPos(byteBuf)); byteBuf.release(); } } diff --git a/rsocket-core/src/test/java/io/rsocket/frame/SetupFrameCodecTest.java b/rsocket-core/src/test/java/io/rsocket/frame/SetupFrameCodecTest.java new file mode 100644 index 000000000..f7d649972 --- /dev/null +++ b/rsocket-core/src/test/java/io/rsocket/frame/SetupFrameCodecTest.java @@ -0,0 +1,57 @@ +package io.rsocket.frame; + +import static org.junit.jupiter.api.Assertions.*; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.Unpooled; +import io.rsocket.Payload; +import io.rsocket.util.DefaultPayload; +import java.util.Arrays; +import org.junit.jupiter.api.Test; + +class SetupFrameCodecTest { + @Test + void testEncodingNoResume() { + ByteBuf metadata = Unpooled.wrappedBuffer(new byte[] {1, 2, 3, 4}); + ByteBuf data = Unpooled.wrappedBuffer(new byte[] {5, 4, 3}); + Payload payload = DefaultPayload.create(data, metadata); + ByteBuf frame = + SetupFrameCodec.encode( + ByteBufAllocator.DEFAULT, false, 5, 500, "metadata_type", "data_type", payload); + + assertEquals(FrameType.SETUP, FrameHeaderCodec.frameType(frame)); + assertFalse(SetupFrameCodec.resumeEnabled(frame)); + assertNull(SetupFrameCodec.resumeToken(frame)); + assertEquals("metadata_type", SetupFrameCodec.metadataMimeType(frame)); + assertEquals("data_type", SetupFrameCodec.dataMimeType(frame)); + assertEquals(metadata, SetupFrameCodec.metadata(frame)); + assertEquals(data, SetupFrameCodec.data(frame)); + assertEquals(SetupFrameCodec.CURRENT_VERSION, SetupFrameCodec.version(frame)); + frame.release(); + } + + @Test + void testEncodingResume() { + byte[] tokenBytes = new byte[65000]; + Arrays.fill(tokenBytes, (byte) 1); + ByteBuf metadata = Unpooled.wrappedBuffer(new byte[] {1, 2, 3, 4}); + ByteBuf data = Unpooled.wrappedBuffer(new byte[] {5, 4, 3}); + Payload payload = DefaultPayload.create(data, metadata); + ByteBuf token = Unpooled.wrappedBuffer(tokenBytes); + ByteBuf frame = + SetupFrameCodec.encode( + ByteBufAllocator.DEFAULT, true, 5, 500, token, "metadata_type", "data_type", payload); + + assertEquals(FrameType.SETUP, FrameHeaderCodec.frameType(frame)); + assertTrue(SetupFrameCodec.honorLease(frame)); + assertTrue(SetupFrameCodec.resumeEnabled(frame)); + assertEquals(token, SetupFrameCodec.resumeToken(frame)); + assertEquals("metadata_type", SetupFrameCodec.metadataMimeType(frame)); + assertEquals("data_type", SetupFrameCodec.dataMimeType(frame)); + assertEquals(metadata, SetupFrameCodec.metadata(frame)); + assertEquals(data, SetupFrameCodec.data(frame)); + assertEquals(SetupFrameCodec.CURRENT_VERSION, SetupFrameCodec.version(frame)); + frame.release(); + } +} diff --git a/rsocket-core/src/test/java/io/rsocket/frame/SetupFrameFlyweightTest.java b/rsocket-core/src/test/java/io/rsocket/frame/SetupFrameFlyweightTest.java deleted file mode 100644 index 128b3ff84..000000000 --- a/rsocket-core/src/test/java/io/rsocket/frame/SetupFrameFlyweightTest.java +++ /dev/null @@ -1,57 +0,0 @@ -package io.rsocket.frame; - -import static org.junit.jupiter.api.Assertions.*; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.Unpooled; -import io.rsocket.Payload; -import io.rsocket.util.DefaultPayload; -import java.util.Arrays; -import org.junit.jupiter.api.Test; - -class SetupFrameFlyweightTest { - @Test - void testEncodingNoResume() { - ByteBuf metadata = Unpooled.wrappedBuffer(new byte[] {1, 2, 3, 4}); - ByteBuf data = Unpooled.wrappedBuffer(new byte[] {5, 4, 3}); - Payload payload = DefaultPayload.create(data, metadata); - ByteBuf frame = - SetupFrameFlyweight.encode( - ByteBufAllocator.DEFAULT, false, 5, 500, "metadata_type", "data_type", payload); - - assertEquals(FrameType.SETUP, FrameHeaderFlyweight.frameType(frame)); - assertFalse(SetupFrameFlyweight.resumeEnabled(frame)); - assertNull(SetupFrameFlyweight.resumeToken(frame)); - assertEquals("metadata_type", SetupFrameFlyweight.metadataMimeType(frame)); - assertEquals("data_type", SetupFrameFlyweight.dataMimeType(frame)); - assertEquals(metadata, SetupFrameFlyweight.metadata(frame)); - assertEquals(data, SetupFrameFlyweight.data(frame)); - assertEquals(SetupFrameFlyweight.CURRENT_VERSION, SetupFrameFlyweight.version(frame)); - frame.release(); - } - - @Test - void testEncodingResume() { - byte[] tokenBytes = new byte[65000]; - Arrays.fill(tokenBytes, (byte) 1); - ByteBuf metadata = Unpooled.wrappedBuffer(new byte[] {1, 2, 3, 4}); - ByteBuf data = Unpooled.wrappedBuffer(new byte[] {5, 4, 3}); - Payload payload = DefaultPayload.create(data, metadata); - ByteBuf token = Unpooled.wrappedBuffer(tokenBytes); - ByteBuf frame = - SetupFrameFlyweight.encode( - ByteBufAllocator.DEFAULT, true, 5, 500, token, "metadata_type", "data_type", payload); - - assertEquals(FrameType.SETUP, FrameHeaderFlyweight.frameType(frame)); - assertTrue(SetupFrameFlyweight.honorLease(frame)); - assertTrue(SetupFrameFlyweight.resumeEnabled(frame)); - assertEquals(token, SetupFrameFlyweight.resumeToken(frame)); - assertEquals("metadata_type", SetupFrameFlyweight.metadataMimeType(frame)); - assertEquals("data_type", SetupFrameFlyweight.dataMimeType(frame)); - assertEquals(metadata, SetupFrameFlyweight.metadata(frame)); - assertEquals(data, SetupFrameFlyweight.data(frame)); - assertEquals(SetupFrameFlyweight.CURRENT_VERSION, SetupFrameFlyweight.version(frame)); - frame.release(); - } -} diff --git a/rsocket-core/src/test/java/io/rsocket/frame/VersionFlyweightTest.java b/rsocket-core/src/test/java/io/rsocket/frame/VersionCodecTest.java similarity index 58% rename from rsocket-core/src/test/java/io/rsocket/frame/VersionFlyweightTest.java rename to rsocket-core/src/test/java/io/rsocket/frame/VersionCodecTest.java index 3f311c7ef..be7fb837b 100644 --- a/rsocket-core/src/test/java/io/rsocket/frame/VersionFlyweightTest.java +++ b/rsocket-core/src/test/java/io/rsocket/frame/VersionCodecTest.java @@ -20,29 +20,29 @@ import org.junit.jupiter.api.Test; -public class VersionFlyweightTest { +public class VersionCodecTest { @Test public void simple() { - int version = VersionFlyweight.encode(1, 0); - assertEquals(1, VersionFlyweight.major(version)); - assertEquals(0, VersionFlyweight.minor(version)); + int version = VersionCodec.encode(1, 0); + assertEquals(1, VersionCodec.major(version)); + assertEquals(0, VersionCodec.minor(version)); assertEquals(0x00010000, version); - assertEquals("1.0", VersionFlyweight.toString(version)); + assertEquals("1.0", VersionCodec.toString(version)); } @Test public void complex() { - int version = VersionFlyweight.encode(0x1234, 0x5678); - assertEquals(0x1234, VersionFlyweight.major(version)); - assertEquals(0x5678, VersionFlyweight.minor(version)); + int version = VersionCodec.encode(0x1234, 0x5678); + assertEquals(0x1234, VersionCodec.major(version)); + assertEquals(0x5678, VersionCodec.minor(version)); assertEquals(0x12345678, version); - assertEquals("4660.22136", VersionFlyweight.toString(version)); + assertEquals("4660.22136", VersionCodec.toString(version)); } @Test public void noShortOverflow() { - int version = VersionFlyweight.encode(43210, 43211); - assertEquals(43210, VersionFlyweight.major(version)); - assertEquals(43211, VersionFlyweight.minor(version)); + int version = VersionCodec.encode(43210, 43211); + assertEquals(43210, VersionCodec.major(version)); + assertEquals(43211, VersionCodec.minor(version)); } } diff --git a/rsocket-core/src/test/java/io/rsocket/internal/ClientServerInputMultiplexerTest.java b/rsocket-core/src/test/java/io/rsocket/internal/ClientServerInputMultiplexerTest.java index efa962c48..63acc40aa 100644 --- a/rsocket-core/src/test/java/io/rsocket/internal/ClientServerInputMultiplexerTest.java +++ b/rsocket-core/src/test/java/io/rsocket/internal/ClientServerInputMultiplexerTest.java @@ -193,11 +193,11 @@ public void serverSplits() { } private ByteBuf resumeFrame() { - return ResumeFrameFlyweight.encode(allocator, Unpooled.EMPTY_BUFFER, 0, 0); + return ResumeFrameCodec.encode(allocator, Unpooled.EMPTY_BUFFER, 0, 0); } private ByteBuf setupFrame() { - return SetupFrameFlyweight.encode( + return SetupFrameCodec.encode( ByteBufAllocator.DEFAULT, false, 0, @@ -208,22 +208,22 @@ private ByteBuf setupFrame() { } private ByteBuf leaseFrame() { - return LeaseFrameFlyweight.encode(allocator, 1_000, 1, Unpooled.EMPTY_BUFFER); + return LeaseFrameCodec.encode(allocator, 1_000, 1, Unpooled.EMPTY_BUFFER); } private ByteBuf errorFrame(int i) { - return ErrorFrameFlyweight.encode(allocator, i, new Exception()); + return ErrorFrameCodec.encode(allocator, i, new Exception()); } private ByteBuf resumeOkFrame() { - return ResumeOkFrameFlyweight.encode(allocator, 0); + return ResumeOkFrameCodec.encode(allocator, 0); } private ByteBuf keepAliveFrame() { - return KeepAliveFrameFlyweight.encode(allocator, false, 0, Unpooled.EMPTY_BUFFER); + return KeepAliveFrameCodec.encode(allocator, false, 0, Unpooled.EMPTY_BUFFER); } private ByteBuf metadataPushFrame() { - return MetadataPushFrameFlyweight.encode(allocator, Unpooled.EMPTY_BUFFER); + return MetadataPushFrameCodec.encode(allocator, Unpooled.EMPTY_BUFFER); } } diff --git a/rsocket-micrometer/src/main/java/io/rsocket/micrometer/MicrometerDuplexConnection.java b/rsocket-micrometer/src/main/java/io/rsocket/micrometer/MicrometerDuplexConnection.java index 9904c2b24..c8b22382a 100644 --- a/rsocket-micrometer/src/main/java/io/rsocket/micrometer/MicrometerDuplexConnection.java +++ b/rsocket-micrometer/src/main/java/io/rsocket/micrometer/MicrometerDuplexConnection.java @@ -22,7 +22,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.rsocket.DuplexConnection; -import io.rsocket.frame.FrameHeaderFlyweight; +import io.rsocket.frame.FrameHeaderCodec; import io.rsocket.frame.FrameType; import io.rsocket.plugins.DuplexConnectionInterceptor.Type; import java.util.Objects; @@ -191,7 +191,7 @@ private static Counter counter( @Override public void accept(ByteBuf frame) { - FrameType frameType = FrameHeaderFlyweight.frameType(frame); + FrameType frameType = FrameHeaderCodec.frameType(frame); switch (frameType) { case SETUP: diff --git a/rsocket-test/src/main/java/io/rsocket/test/TestFrames.java b/rsocket-test/src/main/java/io/rsocket/test/TestFrames.java index 60ff05124..1e66abc5e 100644 --- a/rsocket-test/src/main/java/io/rsocket/test/TestFrames.java +++ b/rsocket-test/src/main/java/io/rsocket/test/TestFrames.java @@ -33,71 +33,69 @@ private TestFrames() {} /** @return {@link ByteBuf} representing test instance of Cancel frame */ public static ByteBuf createTestCancelFrame() { - return CancelFrameFlyweight.encode(allocator, 1); + return CancelFrameCodec.encode(allocator, 1); } /** @return {@link ByteBuf} representing test instance of Error frame */ public static ByteBuf createTestErrorFrame() { - return ErrorFrameFlyweight.encode(allocator, 1, new RuntimeException()); + return ErrorFrameCodec.encode(allocator, 1, new RuntimeException()); } /** @return {@link ByteBuf} representing test instance of Extension frame */ public static ByteBuf createTestExtensionFrame() { - return ExtensionFrameFlyweight.encode( + return ExtensionFrameCodec.encode( allocator, 1, 1, Unpooled.EMPTY_BUFFER, Unpooled.EMPTY_BUFFER); } /** @return {@link ByteBuf} representing test instance of Keep-Alive frame */ public static ByteBuf createTestKeepaliveFrame() { - return KeepAliveFrameFlyweight.encode(allocator, false, 1, Unpooled.EMPTY_BUFFER); + return KeepAliveFrameCodec.encode(allocator, false, 1, Unpooled.EMPTY_BUFFER); } /** @return {@link ByteBuf} representing test instance of Lease frame */ public static ByteBuf createTestLeaseFrame() { - return LeaseFrameFlyweight.encode(allocator, 1, 1, null); + return LeaseFrameCodec.encode(allocator, 1, 1, null); } /** @return {@link ByteBuf} representing test instance of Metadata-Push frame */ public static ByteBuf createTestMetadataPushFrame() { - return MetadataPushFrameFlyweight.encode(allocator, Unpooled.EMPTY_BUFFER); + return MetadataPushFrameCodec.encode(allocator, Unpooled.EMPTY_BUFFER); } /** @return {@link ByteBuf} representing test instance of Payload frame */ public static ByteBuf createTestPayloadFrame() { - return PayloadFrameFlyweight.encode( - allocator, 1, false, true, false, null, Unpooled.EMPTY_BUFFER); + return PayloadFrameCodec.encode(allocator, 1, false, true, false, null, Unpooled.EMPTY_BUFFER); } /** @return {@link ByteBuf} representing test instance of Request-Channel frame */ public static ByteBuf createTestRequestChannelFrame() { - return RequestChannelFrameFlyweight.encode( + return RequestChannelFrameCodec.encode( allocator, 1, false, false, 1, null, Unpooled.EMPTY_BUFFER); } /** @return {@link ByteBuf} representing test instance of Fire-and-Forget frame */ public static ByteBuf createTestRequestFireAndForgetFrame() { - return RequestFireAndForgetFrameFlyweight.encode( - allocator, 1, false, null, Unpooled.EMPTY_BUFFER); + return RequestFireAndForgetFrameCodec.encode(allocator, 1, false, null, Unpooled.EMPTY_BUFFER); } /** @return {@link ByteBuf} representing test instance of Request-N frame */ public static ByteBuf createTestRequestNFrame() { - return RequestNFrameFlyweight.encode(allocator, 1, 1); + return RequestNFrameCodec.encode(allocator, 1, 1); } /** @return {@link ByteBuf} representing test instance of Request-Response frame */ public static ByteBuf createTestRequestResponseFrame() { - return RequestResponseFrameFlyweight.encodeReleasingPayload(allocator, 1, emptyPayload); + return RequestResponseFrameCodec.encodeReleasingPayload(allocator, 1, emptyPayload); } /** @return {@link ByteBuf} representing test instance of Request-Stream frame */ public static ByteBuf createTestRequestStreamFrame() { - return RequestStreamFrameFlyweight.encodeReleasingPayload(allocator, 1, 1L, emptyPayload); + return RequestStreamFrameCodec.encodeReleasingPayload(allocator, 1, 1L, emptyPayload); } /** @return {@link ByteBuf} representing test instance of Setup frame */ public static ByteBuf createTestSetupFrame() { - return SetupFrameFlyweight.encode( + return SetupFrameCodec.encode( allocator, false, 1, diff --git a/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/RSocketLengthCodec.java b/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/RSocketLengthCodec.java index 68d7ab175..e2c134653 100644 --- a/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/RSocketLengthCodec.java +++ b/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/RSocketLengthCodec.java @@ -16,8 +16,8 @@ package io.rsocket.transport.netty; -import static io.rsocket.frame.FrameLengthFlyweight.FRAME_LENGTH_MASK; -import static io.rsocket.frame.FrameLengthFlyweight.FRAME_LENGTH_SIZE; +import static io.rsocket.frame.FrameLengthCodec.FRAME_LENGTH_MASK; +import static io.rsocket.frame.FrameLengthCodec.FRAME_LENGTH_SIZE; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; diff --git a/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/TcpDuplexConnection.java b/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/TcpDuplexConnection.java index d71d6b356..b7081593c 100644 --- a/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/TcpDuplexConnection.java +++ b/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/TcpDuplexConnection.java @@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.rsocket.DuplexConnection; -import io.rsocket.frame.FrameLengthFlyweight; +import io.rsocket.frame.FrameLengthCodec; import io.rsocket.internal.BaseDuplexConnection; import java.util.Objects; import org.reactivestreams.Publisher; @@ -88,7 +88,7 @@ public Mono send(Publisher frames) { private ByteBuf encode(ByteBuf frame) { if (encodeLength) { - return FrameLengthFlyweight.encode(alloc(), frame.readableBytes(), frame); + return FrameLengthCodec.encode(alloc(), frame.readableBytes(), frame); } else { return frame; } @@ -96,7 +96,7 @@ private ByteBuf encode(ByteBuf frame) { private ByteBuf decode(ByteBuf frame) { if (encodeLength) { - return FrameLengthFlyweight.frame(frame).retain(); + return FrameLengthCodec.frame(frame).retain(); } else { return frame; } diff --git a/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/client/WebsocketClientTransport.java b/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/client/WebsocketClientTransport.java index b19621d46..6991728ca 100644 --- a/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/client/WebsocketClientTransport.java +++ b/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/client/WebsocketClientTransport.java @@ -16,7 +16,7 @@ package io.rsocket.transport.netty.client; -import static io.rsocket.frame.FrameLengthFlyweight.FRAME_LENGTH_MASK; +import static io.rsocket.frame.FrameLengthCodec.FRAME_LENGTH_MASK; import static io.rsocket.transport.netty.UriUtils.getPort; import static io.rsocket.transport.netty.UriUtils.isSecure; diff --git a/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/server/WebsocketRouteTransport.java b/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/server/WebsocketRouteTransport.java index 83cb010b7..bd19f18b0 100644 --- a/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/server/WebsocketRouteTransport.java +++ b/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/server/WebsocketRouteTransport.java @@ -16,7 +16,7 @@ package io.rsocket.transport.netty.server; -import static io.rsocket.frame.FrameLengthFlyweight.FRAME_LENGTH_MASK; +import static io.rsocket.frame.FrameLengthCodec.FRAME_LENGTH_MASK; import io.rsocket.Closeable; import io.rsocket.DuplexConnection; diff --git a/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/server/WebsocketServerTransport.java b/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/server/WebsocketServerTransport.java index 4a0331c08..1a0b32cf0 100644 --- a/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/server/WebsocketServerTransport.java +++ b/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/server/WebsocketServerTransport.java @@ -16,7 +16,7 @@ package io.rsocket.transport.netty.server; -import static io.rsocket.frame.FrameLengthFlyweight.FRAME_LENGTH_MASK; +import static io.rsocket.frame.FrameLengthCodec.FRAME_LENGTH_MASK; import io.rsocket.DuplexConnection; import io.rsocket.fragmentation.FragmentationDuplexConnection; diff --git a/rsocket-transport-netty/src/test/java/io/rsocket/transport/netty/client/WebsocketClientTransportTest.java b/rsocket-transport-netty/src/test/java/io/rsocket/transport/netty/client/WebsocketClientTransportTest.java index 905f022f2..fc035c536 100644 --- a/rsocket-transport-netty/src/test/java/io/rsocket/transport/netty/client/WebsocketClientTransportTest.java +++ b/rsocket-transport-netty/src/test/java/io/rsocket/transport/netty/client/WebsocketClientTransportTest.java @@ -16,7 +16,7 @@ package io.rsocket.transport.netty.client; -import static io.rsocket.frame.FrameLengthFlyweight.FRAME_LENGTH_MASK; +import static io.rsocket.frame.FrameLengthCodec.FRAME_LENGTH_MASK; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatNullPointerException; diff --git a/rsocket-transport-netty/src/test/java/io/rsocket/transport/netty/server/WebsocketServerTransportTest.java b/rsocket-transport-netty/src/test/java/io/rsocket/transport/netty/server/WebsocketServerTransportTest.java index 5a2986485..249a3e12a 100644 --- a/rsocket-transport-netty/src/test/java/io/rsocket/transport/netty/server/WebsocketServerTransportTest.java +++ b/rsocket-transport-netty/src/test/java/io/rsocket/transport/netty/server/WebsocketServerTransportTest.java @@ -16,7 +16,7 @@ package io.rsocket.transport.netty.server; -import static io.rsocket.frame.FrameLengthFlyweight.FRAME_LENGTH_MASK; +import static io.rsocket.frame.FrameLengthCodec.FRAME_LENGTH_MASK; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatNullPointerException; From cec7a789c7a644c20b1c48815e5446c8099a8d13 Mon Sep 17 00:00:00 2001 From: Oleh Dokuka Date: Fri, 8 May 2020 20:00:56 +0300 Subject: [PATCH 17/25] provides extra @NonNullApi annotation for all packages (#826) --- build.gradle | 1 - rsocket-core/build.gradle | 2 -- .../io/rsocket/ConnectionSetupPayload.java | 2 +- .../io/rsocket/core/RSocketConnector.java | 2 +- .../io/rsocket/core/RSocketRequester.java | 2 +- .../io/rsocket/core/RSocketResponder.java | 2 +- .../io/rsocket/core/StreamIdSupplier.java | 1 + .../exceptions/ApplicationErrorException.java | 2 +- .../rsocket/exceptions/CanceledException.java | 2 +- .../exceptions/ConnectionCloseException.java | 2 +- .../exceptions/ConnectionErrorException.java | 2 +- .../exceptions/CustomRSocketException.java | 2 +- .../rsocket/exceptions/InvalidException.java | 2 +- .../exceptions/InvalidSetupException.java | 2 +- .../rsocket/exceptions/RejectedException.java | 2 +- .../exceptions/RejectedResumeException.java | 2 +- .../exceptions/RejectedSetupException.java | 2 +- .../io/rsocket/exceptions/SetupException.java | 2 +- .../exceptions/UnsupportedSetupException.java | 2 +- .../FragmentationDuplexConnection.java | 2 +- .../fragmentation/FrameReassembler.java | 8 +++++-- .../io/rsocket/frame/ExtensionFrameCodec.java | 3 ++- .../java/io/rsocket/frame/FrameBodyCodec.java | 5 ++-- .../io/rsocket/frame/GenericFrameCodec.java | 6 +++-- .../io/rsocket/frame/LeaseFrameCodec.java | 6 ++--- .../rsocket/frame/MetadataPushFrameCodec.java | 4 ++++ .../io/rsocket/frame/PayloadFrameCodec.java | 6 +++-- .../frame/RequestChannelFrameCodec.java | 4 +++- .../frame/RequestFireAndForgetFrameCodec.java | 4 +++- .../frame/RequestResponseFrameCodec.java | 4 +++- .../frame/RequestStreamFrameCodec.java | 4 +++- .../io/rsocket/frame/SetupFrameCodec.java | 6 +++-- .../rsocket/frame/decoder/package-info.java | 24 +++++++++++++++++++ .../java/io/rsocket/frame/package-info.java | 3 +++ .../ClientServerInputMultiplexer.java | 1 + .../io/rsocket/internal/package-info.java | 4 +++- .../io/rsocket/keepalive/package-info.java | 4 +++- .../src/main/java/io/rsocket/lease/Lease.java | 4 +--- .../main/java/io/rsocket/lease/LeaseImpl.java | 4 +--- .../rsocket/lease/MissingLeaseException.java | 7 +++--- .../rsocket/lease/ResponderLeaseHandler.java | 2 +- .../java/io/rsocket/lease/package-info.java | 4 +++- .../io/rsocket/metadata/package-info.java | 3 +++ .../main/java/io/rsocket/package-info.java | 3 +++ .../java/io/rsocket/plugins/package-info.java | 3 +++ .../io/rsocket/resume/SessionManager.java | 2 +- .../java/io/rsocket/resume/package-info.java | 4 +++- .../io/rsocket/transport/package-info.java | 4 +++- .../java/io/rsocket/util/ByteBufPayload.java | 2 +- .../java/io/rsocket/util/DefaultPayload.java | 2 +- .../java/io/rsocket/util/package-info.java | 4 +++- .../core/ConnectionSetupPayloadTest.java | 2 +- .../core/RSocketRequesterSubscribersTest.java | 2 +- .../io/rsocket/frame/LeaseFrameCodecTest.java | 2 +- .../io/rsocket/frame/SetupFrameCodecTest.java | 2 +- .../rsocket/client/filter/package-info.java | 20 ++++++++++++++++ .../java/io/rsocket/client/package-info.java | 20 ++++++++++++++++ .../java/io/rsocket/stat/package-info.java | 20 ++++++++++++++++ rsocket-micrometer/build.gradle | 2 -- rsocket-test/build.gradle | 2 -- rsocket-transport-local/build.gradle | 2 -- rsocket-transport-netty/build.gradle | 2 -- .../netty/client/TcpClientTransport.java | 2 +- .../client/WebsocketClientTransport.java | 8 ++++--- .../netty/server/CloseableChannel.java | 2 +- .../netty/TcpSecureTransportTest.java | 4 ++-- .../netty/WebsocketSecureTransportTest.java | 4 ++-- 67 files changed, 199 insertions(+), 79 deletions(-) create mode 100644 rsocket-core/src/main/java/io/rsocket/frame/decoder/package-info.java create mode 100644 rsocket-load-balancer/src/main/java/io/rsocket/client/filter/package-info.java create mode 100644 rsocket-load-balancer/src/main/java/io/rsocket/client/package-info.java create mode 100644 rsocket-load-balancer/src/main/java/io/rsocket/stat/package-info.java diff --git a/build.gradle b/build.gradle index 2c7757e0f..f579b3ae0 100644 --- a/build.gradle +++ b/build.gradle @@ -62,7 +62,6 @@ subprojects { dependencies { dependency "ch.qos.logback:logback-classic:${ext['logback.version']}" - dependency "com.google.code.findbugs:jsr305:${ext['findbugs.version']}" dependency "io.netty:netty-tcnative-boringssl-static:${ext['netty-boringssl.version']}" dependency "io.micrometer:micrometer-core:${ext['micrometer.version']}" dependency "org.assertj:assertj-core:${ext['assertj.version']}" diff --git a/rsocket-core/build.gradle b/rsocket-core/build.gradle index ca2ae0e65..41adbd7a8 100644 --- a/rsocket-core/build.gradle +++ b/rsocket-core/build.gradle @@ -29,8 +29,6 @@ dependencies { implementation 'org.slf4j:slf4j-api' - compileOnly 'com.google.code.findbugs:jsr305' - testImplementation 'io.projectreactor:reactor-test' testImplementation 'org.assertj:assertj-core' testImplementation 'org.junit.jupiter:junit-jupiter-api' diff --git a/rsocket-core/src/main/java/io/rsocket/ConnectionSetupPayload.java b/rsocket-core/src/main/java/io/rsocket/ConnectionSetupPayload.java index bd4582e2b..ece2aa9fa 100644 --- a/rsocket-core/src/main/java/io/rsocket/ConnectionSetupPayload.java +++ b/rsocket-core/src/main/java/io/rsocket/ConnectionSetupPayload.java @@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf; import io.netty.util.AbstractReferenceCounted; import io.rsocket.core.DefaultConnectionSetupPayload; -import javax.annotation.Nullable; +import reactor.util.annotation.Nullable; /** * Exposes information from the {@code SETUP} frame to a server, as well as to client responders. diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java index b69610f3f..38393c27d 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java @@ -41,10 +41,10 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Supplier; -import javax.annotation.Nullable; import reactor.core.Disposable; import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; +import reactor.util.annotation.Nullable; import reactor.util.retry.Retry; /** diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java index 846eaa922..068797d39 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java @@ -55,7 +55,6 @@ import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import java.util.function.Consumer; import java.util.function.Supplier; -import javax.annotation.Nullable; import org.reactivestreams.Processor; import org.reactivestreams.Publisher; import org.reactivestreams.Subscriber; @@ -68,6 +67,7 @@ import reactor.core.publisher.SignalType; import reactor.core.publisher.UnicastProcessor; import reactor.core.scheduler.Scheduler; +import reactor.util.annotation.Nullable; import reactor.util.concurrent.Queues; /** diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java index b9d3ea794..dce182b49 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java @@ -39,7 +39,6 @@ import java.util.function.Consumer; import java.util.function.LongConsumer; import java.util.function.Supplier; -import javax.annotation.Nullable; import org.reactivestreams.Processor; import org.reactivestreams.Publisher; import org.reactivestreams.Subscriber; @@ -47,6 +46,7 @@ import reactor.core.Disposable; import reactor.core.Exceptions; import reactor.core.publisher.*; +import reactor.util.annotation.Nullable; import reactor.util.concurrent.Queues; /** Responder side of RSocket. Receives {@link ByteBuf}s from a peer's {@link RSocketRequester} */ diff --git a/rsocket-core/src/main/java/io/rsocket/core/StreamIdSupplier.java b/rsocket-core/src/main/java/io/rsocket/core/StreamIdSupplier.java index 7f4d7b7b3..15d39c993 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/StreamIdSupplier.java +++ b/rsocket-core/src/main/java/io/rsocket/core/StreamIdSupplier.java @@ -17,6 +17,7 @@ import io.netty.util.collection.IntObjectMap; +/** This API is not thread-safe and must be strictly used in serialized fashion */ final class StreamIdSupplier { private static final int MASK = 0x7FFFFFFF; diff --git a/rsocket-core/src/main/java/io/rsocket/exceptions/ApplicationErrorException.java b/rsocket-core/src/main/java/io/rsocket/exceptions/ApplicationErrorException.java index e617b82d8..cd0d46754 100644 --- a/rsocket-core/src/main/java/io/rsocket/exceptions/ApplicationErrorException.java +++ b/rsocket-core/src/main/java/io/rsocket/exceptions/ApplicationErrorException.java @@ -17,7 +17,7 @@ package io.rsocket.exceptions; import io.rsocket.frame.ErrorFrameCodec; -import javax.annotation.Nullable; +import reactor.util.annotation.Nullable; /** * Application layer logic generating a Reactive Streams {@code onError} event. diff --git a/rsocket-core/src/main/java/io/rsocket/exceptions/CanceledException.java b/rsocket-core/src/main/java/io/rsocket/exceptions/CanceledException.java index 3c5fc7420..d51ba0fb7 100644 --- a/rsocket-core/src/main/java/io/rsocket/exceptions/CanceledException.java +++ b/rsocket-core/src/main/java/io/rsocket/exceptions/CanceledException.java @@ -17,7 +17,7 @@ package io.rsocket.exceptions; import io.rsocket.frame.ErrorFrameCodec; -import javax.annotation.Nullable; +import reactor.util.annotation.Nullable; /** * The Responder canceled the request but may have started processing it (similar to REJECTED but diff --git a/rsocket-core/src/main/java/io/rsocket/exceptions/ConnectionCloseException.java b/rsocket-core/src/main/java/io/rsocket/exceptions/ConnectionCloseException.java index 5cff2c821..80324aa90 100644 --- a/rsocket-core/src/main/java/io/rsocket/exceptions/ConnectionCloseException.java +++ b/rsocket-core/src/main/java/io/rsocket/exceptions/ConnectionCloseException.java @@ -17,7 +17,7 @@ package io.rsocket.exceptions; import io.rsocket.frame.ErrorFrameCodec; -import javax.annotation.Nullable; +import reactor.util.annotation.Nullable; /** * The connection is being terminated. Sender or Receiver of this frame MUST wait for outstanding diff --git a/rsocket-core/src/main/java/io/rsocket/exceptions/ConnectionErrorException.java b/rsocket-core/src/main/java/io/rsocket/exceptions/ConnectionErrorException.java index 3fcb8f5de..b44714f7e 100644 --- a/rsocket-core/src/main/java/io/rsocket/exceptions/ConnectionErrorException.java +++ b/rsocket-core/src/main/java/io/rsocket/exceptions/ConnectionErrorException.java @@ -17,7 +17,7 @@ package io.rsocket.exceptions; import io.rsocket.frame.ErrorFrameCodec; -import javax.annotation.Nullable; +import reactor.util.annotation.Nullable; /** * The connection is being terminated. Sender or Receiver of this frame MAY close the connection diff --git a/rsocket-core/src/main/java/io/rsocket/exceptions/CustomRSocketException.java b/rsocket-core/src/main/java/io/rsocket/exceptions/CustomRSocketException.java index 18f488ba0..079b561f9 100644 --- a/rsocket-core/src/main/java/io/rsocket/exceptions/CustomRSocketException.java +++ b/rsocket-core/src/main/java/io/rsocket/exceptions/CustomRSocketException.java @@ -17,7 +17,7 @@ package io.rsocket.exceptions; import io.rsocket.frame.ErrorFrameCodec; -import javax.annotation.Nullable; +import reactor.util.annotation.Nullable; public class CustomRSocketException extends RSocketException { private static final long serialVersionUID = 7873267740343446585L; diff --git a/rsocket-core/src/main/java/io/rsocket/exceptions/InvalidException.java b/rsocket-core/src/main/java/io/rsocket/exceptions/InvalidException.java index 2428d1e7e..a1b77b8dd 100644 --- a/rsocket-core/src/main/java/io/rsocket/exceptions/InvalidException.java +++ b/rsocket-core/src/main/java/io/rsocket/exceptions/InvalidException.java @@ -17,7 +17,7 @@ package io.rsocket.exceptions; import io.rsocket.frame.ErrorFrameCodec; -import javax.annotation.Nullable; +import reactor.util.annotation.Nullable; /** * The request is invalid. diff --git a/rsocket-core/src/main/java/io/rsocket/exceptions/InvalidSetupException.java b/rsocket-core/src/main/java/io/rsocket/exceptions/InvalidSetupException.java index 57da19bb6..b0889c5a6 100644 --- a/rsocket-core/src/main/java/io/rsocket/exceptions/InvalidSetupException.java +++ b/rsocket-core/src/main/java/io/rsocket/exceptions/InvalidSetupException.java @@ -17,7 +17,7 @@ package io.rsocket.exceptions; import io.rsocket.frame.ErrorFrameCodec; -import javax.annotation.Nullable; +import reactor.util.annotation.Nullable; /** * The Setup frame is invalid for the server (it could be that the client is too recent for the old diff --git a/rsocket-core/src/main/java/io/rsocket/exceptions/RejectedException.java b/rsocket-core/src/main/java/io/rsocket/exceptions/RejectedException.java index c87a60243..baed84e1b 100644 --- a/rsocket-core/src/main/java/io/rsocket/exceptions/RejectedException.java +++ b/rsocket-core/src/main/java/io/rsocket/exceptions/RejectedException.java @@ -17,7 +17,7 @@ package io.rsocket.exceptions; import io.rsocket.frame.ErrorFrameCodec; -import javax.annotation.Nullable; +import reactor.util.annotation.Nullable; /** * Despite being a valid request, the Responder decided to reject it. The Responder guarantees that diff --git a/rsocket-core/src/main/java/io/rsocket/exceptions/RejectedResumeException.java b/rsocket-core/src/main/java/io/rsocket/exceptions/RejectedResumeException.java index 8a6ea2244..8a99fcffb 100644 --- a/rsocket-core/src/main/java/io/rsocket/exceptions/RejectedResumeException.java +++ b/rsocket-core/src/main/java/io/rsocket/exceptions/RejectedResumeException.java @@ -17,7 +17,7 @@ package io.rsocket.exceptions; import io.rsocket.frame.ErrorFrameCodec; -import javax.annotation.Nullable; +import reactor.util.annotation.Nullable; /** * The server rejected the resume, it can specify the reason in the payload. diff --git a/rsocket-core/src/main/java/io/rsocket/exceptions/RejectedSetupException.java b/rsocket-core/src/main/java/io/rsocket/exceptions/RejectedSetupException.java index 972b430a7..c09a27e32 100644 --- a/rsocket-core/src/main/java/io/rsocket/exceptions/RejectedSetupException.java +++ b/rsocket-core/src/main/java/io/rsocket/exceptions/RejectedSetupException.java @@ -17,7 +17,7 @@ package io.rsocket.exceptions; import io.rsocket.frame.ErrorFrameCodec; -import javax.annotation.Nullable; +import reactor.util.annotation.Nullable; /** * The server rejected the setup, it can specify the reason in the payload. diff --git a/rsocket-core/src/main/java/io/rsocket/exceptions/SetupException.java b/rsocket-core/src/main/java/io/rsocket/exceptions/SetupException.java index 158e5410d..ed979c9e6 100644 --- a/rsocket-core/src/main/java/io/rsocket/exceptions/SetupException.java +++ b/rsocket-core/src/main/java/io/rsocket/exceptions/SetupException.java @@ -17,7 +17,7 @@ package io.rsocket.exceptions; import io.rsocket.frame.ErrorFrameCodec; -import javax.annotation.Nullable; +import reactor.util.annotation.Nullable; /** The root of the setup exception hierarchy. */ public abstract class SetupException extends RSocketException { diff --git a/rsocket-core/src/main/java/io/rsocket/exceptions/UnsupportedSetupException.java b/rsocket-core/src/main/java/io/rsocket/exceptions/UnsupportedSetupException.java index 3282c9750..7429ccd98 100644 --- a/rsocket-core/src/main/java/io/rsocket/exceptions/UnsupportedSetupException.java +++ b/rsocket-core/src/main/java/io/rsocket/exceptions/UnsupportedSetupException.java @@ -17,7 +17,7 @@ package io.rsocket.exceptions; import io.rsocket.frame.ErrorFrameCodec; -import javax.annotation.Nullable; +import reactor.util.annotation.Nullable; /** * Some (or all) of the parameters specified by the client are unsupported by the server. diff --git a/rsocket-core/src/main/java/io/rsocket/fragmentation/FragmentationDuplexConnection.java b/rsocket-core/src/main/java/io/rsocket/fragmentation/FragmentationDuplexConnection.java index 5192ffead..5d89bb9ad 100644 --- a/rsocket-core/src/main/java/io/rsocket/fragmentation/FragmentationDuplexConnection.java +++ b/rsocket-core/src/main/java/io/rsocket/fragmentation/FragmentationDuplexConnection.java @@ -25,12 +25,12 @@ import io.rsocket.frame.FrameLengthCodec; import io.rsocket.frame.FrameType; import java.util.Objects; -import javax.annotation.Nullable; import org.reactivestreams.Publisher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import reactor.util.annotation.Nullable; /** * A {@link DuplexConnection} implementation that fragments and reassembles {@link ByteBuf}s. diff --git a/rsocket-core/src/main/java/io/rsocket/fragmentation/FrameReassembler.java b/rsocket-core/src/main/java/io/rsocket/fragmentation/FrameReassembler.java index 1e96bd1fc..52068e5de 100644 --- a/rsocket-core/src/main/java/io/rsocket/fragmentation/FrameReassembler.java +++ b/rsocket-core/src/main/java/io/rsocket/fragmentation/FrameReassembler.java @@ -29,6 +29,7 @@ import org.slf4j.LoggerFactory; import reactor.core.Disposable; import reactor.core.publisher.SynchronousSink; +import reactor.util.annotation.Nullable; /** * The implementation of the RSocket reassembly behavior. @@ -83,6 +84,7 @@ public boolean isDisposed() { return get(); } + @Nullable synchronized ByteBuf getHeader(int streamId) { return headers.get(streamId); } @@ -109,14 +111,17 @@ synchronized CompositeByteBuf getData(int streamId) { return byteBuf; } + @Nullable synchronized ByteBuf removeHeader(int streamId) { return headers.remove(streamId); } + @Nullable synchronized CompositeByteBuf removeMetadata(int streamId) { return metadata.remove(streamId); } + @Nullable synchronized CompositeByteBuf removeData(int streamId) { return data.remove(streamId); } @@ -236,7 +241,6 @@ void reassembleFrame(ByteBuf frame, SynchronousSink sink) { case CANCEL: case ERROR: cancelAssemble(streamId); - default: } if (!frameType.isFragmentable()) { @@ -270,7 +274,7 @@ private ByteBuf assembleFrameWithMetadata(ByteBuf frame, int streamId, ByteBuf h metadata = PayloadFrameCodec.metadata(frame).retain(); } } else { - metadata = cm != null ? cm : null; + metadata = cm; } ByteBuf data = assembleData(frame, streamId); diff --git a/rsocket-core/src/main/java/io/rsocket/frame/ExtensionFrameCodec.java b/rsocket-core/src/main/java/io/rsocket/frame/ExtensionFrameCodec.java index bf30b9556..418926596 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/ExtensionFrameCodec.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/ExtensionFrameCodec.java @@ -2,7 +2,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; -import javax.annotation.Nullable; +import reactor.util.annotation.Nullable; public class ExtensionFrameCodec { private ExtensionFrameCodec() {} @@ -49,6 +49,7 @@ public static ByteBuf data(ByteBuf byteBuf) { return data; } + @Nullable public static ByteBuf metadata(ByteBuf byteBuf) { FrameHeaderCodec.ensureFrameType(FrameType.EXT, byteBuf); diff --git a/rsocket-core/src/main/java/io/rsocket/frame/FrameBodyCodec.java b/rsocket-core/src/main/java/io/rsocket/frame/FrameBodyCodec.java index 3256d4426..ea011e503 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/FrameBodyCodec.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/FrameBodyCodec.java @@ -3,6 +3,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.Unpooled; +import reactor.util.annotation.Nullable; class FrameBodyCodec { public static final int FRAME_LENGTH_MASK = 0xFFFFFF; @@ -33,9 +34,9 @@ private static int decodeLength(final ByteBuf byteBuf) { static ByteBuf encode( ByteBufAllocator allocator, final ByteBuf header, - ByteBuf metadata, + @Nullable ByteBuf metadata, boolean hasMetadata, - ByteBuf data) { + @Nullable ByteBuf data) { final boolean addData; if (data != null) { diff --git a/rsocket-core/src/main/java/io/rsocket/frame/GenericFrameCodec.java b/rsocket-core/src/main/java/io/rsocket/frame/GenericFrameCodec.java index 65e7eeeea..56a93d869 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/GenericFrameCodec.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/GenericFrameCodec.java @@ -4,7 +4,7 @@ import io.netty.buffer.ByteBufAllocator; import io.netty.util.IllegalReferenceCountException; import io.rsocket.Payload; -import javax.annotation.Nullable; +import reactor.util.annotation.Nullable; class GenericFrameCodec { @@ -75,7 +75,7 @@ static ByteBuf encode( boolean next, int requestN, @Nullable ByteBuf metadata, - ByteBuf data) { + @Nullable ByteBuf data) { final boolean hasMetadata = metadata != null; @@ -115,6 +115,7 @@ static ByteBuf data(ByteBuf byteBuf) { return data; } + @Nullable static ByteBuf metadata(ByteBuf byteBuf) { boolean hasMetadata = FrameHeaderCodec.hasMetadata(byteBuf); if (!hasMetadata) { @@ -136,6 +137,7 @@ static ByteBuf dataWithRequestN(ByteBuf byteBuf) { return data; } + @Nullable static ByteBuf metadataWithRequestN(ByteBuf byteBuf) { boolean hasMetadata = FrameHeaderCodec.hasMetadata(byteBuf); if (!hasMetadata) { diff --git a/rsocket-core/src/main/java/io/rsocket/frame/LeaseFrameCodec.java b/rsocket-core/src/main/java/io/rsocket/frame/LeaseFrameCodec.java index cafd80104..f20c25d3b 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/LeaseFrameCodec.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/LeaseFrameCodec.java @@ -2,8 +2,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.Unpooled; -import javax.annotation.Nullable; +import reactor.util.annotation.Nullable; public class LeaseFrameCodec { @@ -67,6 +66,7 @@ public static int numRequests(final ByteBuf byteBuf) { return numRequests; } + @Nullable public static ByteBuf metadata(final ByteBuf byteBuf) { FrameHeaderCodec.ensureFrameType(FrameType.LEASE, byteBuf); if (FrameHeaderCodec.hasMetadata(byteBuf)) { @@ -77,7 +77,7 @@ public static ByteBuf metadata(final ByteBuf byteBuf) { byteBuf.resetReaderIndex(); return metadata; } else { - return Unpooled.EMPTY_BUFFER; + return null; } } } diff --git a/rsocket-core/src/main/java/io/rsocket/frame/MetadataPushFrameCodec.java b/rsocket-core/src/main/java/io/rsocket/frame/MetadataPushFrameCodec.java index 62c8a17dc..d8ffe3eef 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/MetadataPushFrameCodec.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/MetadataPushFrameCodec.java @@ -8,6 +8,10 @@ public class MetadataPushFrameCodec { public static ByteBuf encodeReleasingPayload(ByteBufAllocator allocator, Payload payload) { + if (!payload.hasMetadata()) { + throw new IllegalStateException( + "Metadata push requires to have metadata present" + " in the given Payload"); + } final ByteBuf metadata = payload.metadata().retain(); // releasing payload safely since it can be already released wheres we have to release retained // data and metadata as well diff --git a/rsocket-core/src/main/java/io/rsocket/frame/PayloadFrameCodec.java b/rsocket-core/src/main/java/io/rsocket/frame/PayloadFrameCodec.java index 8a7e6427a..1ae9c6750 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/PayloadFrameCodec.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/PayloadFrameCodec.java @@ -3,6 +3,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.rsocket.Payload; +import reactor.util.annotation.Nullable; public class PayloadFrameCodec { @@ -37,8 +38,8 @@ public static ByteBuf encode( boolean fragmentFollows, boolean complete, boolean next, - ByteBuf metadata, - ByteBuf data) { + @Nullable ByteBuf metadata, + @Nullable ByteBuf data) { return GenericFrameCodec.encode( allocator, FrameType.PAYLOAD, streamId, fragmentFollows, complete, next, 0, metadata, data); @@ -48,6 +49,7 @@ public static ByteBuf data(ByteBuf byteBuf) { return GenericFrameCodec.data(byteBuf); } + @Nullable public static ByteBuf metadata(ByteBuf byteBuf) { return GenericFrameCodec.metadata(byteBuf); } diff --git a/rsocket-core/src/main/java/io/rsocket/frame/RequestChannelFrameCodec.java b/rsocket-core/src/main/java/io/rsocket/frame/RequestChannelFrameCodec.java index 2ff887043..60906083d 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/RequestChannelFrameCodec.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/RequestChannelFrameCodec.java @@ -3,6 +3,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.rsocket.Payload; +import reactor.util.annotation.Nullable; public class RequestChannelFrameCodec { @@ -31,7 +32,7 @@ public static ByteBuf encode( boolean fragmentFollows, boolean complete, long initialRequestN, - ByteBuf metadata, + @Nullable ByteBuf metadata, ByteBuf data) { if (initialRequestN < 1) { @@ -56,6 +57,7 @@ public static ByteBuf data(ByteBuf byteBuf) { return GenericFrameCodec.dataWithRequestN(byteBuf); } + @Nullable public static ByteBuf metadata(ByteBuf byteBuf) { return GenericFrameCodec.metadataWithRequestN(byteBuf); } diff --git a/rsocket-core/src/main/java/io/rsocket/frame/RequestFireAndForgetFrameCodec.java b/rsocket-core/src/main/java/io/rsocket/frame/RequestFireAndForgetFrameCodec.java index ddb5bc5d7..b91199179 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/RequestFireAndForgetFrameCodec.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/RequestFireAndForgetFrameCodec.java @@ -3,6 +3,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.rsocket.Payload; +import reactor.util.annotation.Nullable; public class RequestFireAndForgetFrameCodec { @@ -19,7 +20,7 @@ public static ByteBuf encode( ByteBufAllocator allocator, int streamId, boolean fragmentFollows, - ByteBuf metadata, + @Nullable ByteBuf metadata, ByteBuf data) { return GenericFrameCodec.encode( @@ -30,6 +31,7 @@ public static ByteBuf data(ByteBuf byteBuf) { return GenericFrameCodec.data(byteBuf); } + @Nullable public static ByteBuf metadata(ByteBuf byteBuf) { return GenericFrameCodec.metadata(byteBuf); } diff --git a/rsocket-core/src/main/java/io/rsocket/frame/RequestResponseFrameCodec.java b/rsocket-core/src/main/java/io/rsocket/frame/RequestResponseFrameCodec.java index 884a8293b..4a37acfd5 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/RequestResponseFrameCodec.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/RequestResponseFrameCodec.java @@ -3,6 +3,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.rsocket.Payload; +import reactor.util.annotation.Nullable; public class RequestResponseFrameCodec { @@ -19,7 +20,7 @@ public static ByteBuf encode( ByteBufAllocator allocator, int streamId, boolean fragmentFollows, - ByteBuf metadata, + @Nullable ByteBuf metadata, ByteBuf data) { return GenericFrameCodec.encode( allocator, FrameType.REQUEST_RESPONSE, streamId, fragmentFollows, metadata, data); @@ -29,6 +30,7 @@ public static ByteBuf data(ByteBuf byteBuf) { return GenericFrameCodec.data(byteBuf); } + @Nullable public static ByteBuf metadata(ByteBuf byteBuf) { return GenericFrameCodec.metadata(byteBuf); } diff --git a/rsocket-core/src/main/java/io/rsocket/frame/RequestStreamFrameCodec.java b/rsocket-core/src/main/java/io/rsocket/frame/RequestStreamFrameCodec.java index 9853a8b54..2f5dbf0d8 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/RequestStreamFrameCodec.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/RequestStreamFrameCodec.java @@ -3,6 +3,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.rsocket.Payload; +import reactor.util.annotation.Nullable; public class RequestStreamFrameCodec { @@ -26,7 +27,7 @@ public static ByteBuf encode( int streamId, boolean fragmentFollows, long initialRequestN, - ByteBuf metadata, + @Nullable ByteBuf metadata, ByteBuf data) { if (initialRequestN < 1) { @@ -51,6 +52,7 @@ public static ByteBuf data(ByteBuf byteBuf) { return GenericFrameCodec.dataWithRequestN(byteBuf); } + @Nullable public static ByteBuf metadata(ByteBuf byteBuf) { return GenericFrameCodec.metadataWithRequestN(byteBuf); } diff --git a/rsocket-core/src/main/java/io/rsocket/frame/SetupFrameCodec.java b/rsocket-core/src/main/java/io/rsocket/frame/SetupFrameCodec.java index d6f7431e4..547e2436e 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/SetupFrameCodec.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/SetupFrameCodec.java @@ -6,6 +6,7 @@ import io.netty.buffer.Unpooled; import io.rsocket.Payload; import java.nio.charset.StandardCharsets; +import reactor.util.annotation.Nullable; public class SetupFrameCodec { /** @@ -61,7 +62,7 @@ public static ByteBuf encode( int flags = 0; - if (resumeToken != null && resumeToken.readableBytes() > 0) { + if (resumeToken.readableBytes() > 0) { flags |= FLAGS_RESUME_ENABLE; } @@ -163,7 +164,7 @@ public static ByteBuf resumeToken(ByteBuf byteBuf) { byteBuf.resetReaderIndex(); return resumeToken; } else { - return null; + return Unpooled.EMPTY_BUFFER; } } @@ -186,6 +187,7 @@ public static String dataMimeType(ByteBuf byteBuf) { return mimeType; } + @Nullable public static ByteBuf metadata(ByteBuf byteBuf) { boolean hasMetadata = FrameHeaderCodec.hasMetadata(byteBuf); if (!hasMetadata) { diff --git a/rsocket-core/src/main/java/io/rsocket/frame/decoder/package-info.java b/rsocket-core/src/main/java/io/rsocket/frame/decoder/package-info.java new file mode 100644 index 000000000..82e8acaf3 --- /dev/null +++ b/rsocket-core/src/main/java/io/rsocket/frame/decoder/package-info.java @@ -0,0 +1,24 @@ +/* + * Copyright 2015-2020 the original author or authors. + * + * Licensed 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. + */ + +/** + * Support for encoding and decoding of RSocket frames to and from {@link io.rsocket.Payload + * Payload}. + */ +@NonNullApi +package io.rsocket.frame.decoder; + +import reactor.util.annotation.NonNullApi; diff --git a/rsocket-core/src/main/java/io/rsocket/frame/package-info.java b/rsocket-core/src/main/java/io/rsocket/frame/package-info.java index 1d02ebca0..69f6d6860 100644 --- a/rsocket-core/src/main/java/io/rsocket/frame/package-info.java +++ b/rsocket-core/src/main/java/io/rsocket/frame/package-info.java @@ -18,4 +18,7 @@ * Support for encoding and decoding of RSocket frames to and from {@link io.rsocket.Payload * Payload}. */ +@NonNullApi package io.rsocket.frame; + +import reactor.util.annotation.NonNullApi; diff --git a/rsocket-core/src/main/java/io/rsocket/internal/ClientServerInputMultiplexer.java b/rsocket-core/src/main/java/io/rsocket/internal/ClientServerInputMultiplexer.java index c294d6539..0d24c51d8 100644 --- a/rsocket-core/src/main/java/io/rsocket/internal/ClientServerInputMultiplexer.java +++ b/rsocket-core/src/main/java/io/rsocket/internal/ClientServerInputMultiplexer.java @@ -161,6 +161,7 @@ private static class InternalDuplexConnection implements DuplexConnection { private final MonoProcessor>[] processors; private final boolean debugEnabled; + @SafeVarargs public InternalDuplexConnection( DuplexConnection source, MonoProcessor>... processors) { this.source = source; diff --git a/rsocket-core/src/main/java/io/rsocket/internal/package-info.java b/rsocket-core/src/main/java/io/rsocket/internal/package-info.java index 09918f3d1..07ddfab41 100644 --- a/rsocket-core/src/main/java/io/rsocket/internal/package-info.java +++ b/rsocket-core/src/main/java/io/rsocket/internal/package-info.java @@ -18,5 +18,7 @@ * Internal package and must not be used outside this project. There are no guarantees for * API compatibility. */ -@javax.annotation.ParametersAreNonnullByDefault +@NonNullApi package io.rsocket.internal; + +import reactor.util.annotation.NonNullApi; diff --git a/rsocket-core/src/main/java/io/rsocket/keepalive/package-info.java b/rsocket-core/src/main/java/io/rsocket/keepalive/package-info.java index ce8a2f3fb..d94a93cad 100644 --- a/rsocket-core/src/main/java/io/rsocket/keepalive/package-info.java +++ b/rsocket-core/src/main/java/io/rsocket/keepalive/package-info.java @@ -15,5 +15,7 @@ */ /** Support classes for sending and keeping track of KEEPALIVE frames from the remote. */ -@javax.annotation.ParametersAreNonnullByDefault +@NonNullApi package io.rsocket.keepalive; + +import reactor.util.annotation.NonNullApi; diff --git a/rsocket-core/src/main/java/io/rsocket/lease/Lease.java b/rsocket-core/src/main/java/io/rsocket/lease/Lease.java index b9d99f88a..673b4a480 100644 --- a/rsocket-core/src/main/java/io/rsocket/lease/Lease.java +++ b/rsocket-core/src/main/java/io/rsocket/lease/Lease.java @@ -19,8 +19,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.rsocket.Availability; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; +import reactor.util.annotation.Nullable; /** A contract for RSocket lease, which is sent by a request acceptor and is time bound. */ public interface Lease extends Availability { @@ -78,7 +77,6 @@ default int getRemainingTimeToLiveMillis(long now) { * * @return Metadata for the lease. */ - @Nonnull ByteBuf getMetadata(); /** diff --git a/rsocket-core/src/main/java/io/rsocket/lease/LeaseImpl.java b/rsocket-core/src/main/java/io/rsocket/lease/LeaseImpl.java index 63b0433cb..7abb8aab9 100644 --- a/rsocket-core/src/main/java/io/rsocket/lease/LeaseImpl.java +++ b/rsocket-core/src/main/java/io/rsocket/lease/LeaseImpl.java @@ -19,8 +19,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import java.util.concurrent.atomic.AtomicInteger; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; +import reactor.util.annotation.Nullable; public class LeaseImpl implements Lease { private final int timeToLiveMillis; @@ -60,7 +59,6 @@ public int getStartingAllowedRequests() { return startingAllowedRequests; } - @Nonnull @Override public ByteBuf getMetadata() { return metadata; diff --git a/rsocket-core/src/main/java/io/rsocket/lease/MissingLeaseException.java b/rsocket-core/src/main/java/io/rsocket/lease/MissingLeaseException.java index 734d16d07..3b6cec62c 100644 --- a/rsocket-core/src/main/java/io/rsocket/lease/MissingLeaseException.java +++ b/rsocket-core/src/main/java/io/rsocket/lease/MissingLeaseException.java @@ -17,17 +17,16 @@ import io.rsocket.exceptions.RejectedException; import java.util.Objects; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; +import reactor.util.annotation.Nullable; public class MissingLeaseException extends RejectedException { private static final long serialVersionUID = -6169748673403858959L; - public MissingLeaseException(@Nonnull Lease lease, @Nonnull String tag) { + public MissingLeaseException(Lease lease, String tag) { super(leaseMessage(Objects.requireNonNull(lease), Objects.requireNonNull(tag))); } - public MissingLeaseException(@Nonnull String tag) { + public MissingLeaseException(String tag) { super(leaseMessage(null, Objects.requireNonNull(tag))); } diff --git a/rsocket-core/src/main/java/io/rsocket/lease/ResponderLeaseHandler.java b/rsocket-core/src/main/java/io/rsocket/lease/ResponderLeaseHandler.java index 5f000cb30..2035ade87 100644 --- a/rsocket-core/src/main/java/io/rsocket/lease/ResponderLeaseHandler.java +++ b/rsocket-core/src/main/java/io/rsocket/lease/ResponderLeaseHandler.java @@ -23,10 +23,10 @@ import java.util.Optional; import java.util.function.Consumer; import java.util.function.Function; -import javax.annotation.Nullable; import reactor.core.Disposable; import reactor.core.Disposables; import reactor.core.publisher.Flux; +import reactor.util.annotation.Nullable; public interface ResponderLeaseHandler extends Availability { diff --git a/rsocket-core/src/main/java/io/rsocket/lease/package-info.java b/rsocket-core/src/main/java/io/rsocket/lease/package-info.java index ce1956628..342ab27f7 100644 --- a/rsocket-core/src/main/java/io/rsocket/lease/package-info.java +++ b/rsocket-core/src/main/java/io/rsocket/lease/package-info.java @@ -21,5 +21,7 @@ * href="https://github.com/rsocket/rsocket/blob/master/Protocol.md#resuming-operation">Resuming * Operation */ -@javax.annotation.ParametersAreNonnullByDefault +@NonNullApi package io.rsocket.lease; + +import reactor.util.annotation.NonNullApi; diff --git a/rsocket-core/src/main/java/io/rsocket/metadata/package-info.java b/rsocket-core/src/main/java/io/rsocket/metadata/package-info.java index b1bc45ff0..3fb9ae1d6 100644 --- a/rsocket-core/src/main/java/io/rsocket/metadata/package-info.java +++ b/rsocket-core/src/main/java/io/rsocket/metadata/package-info.java @@ -19,4 +19,7 @@ * href="https://github.com/rsocket/rsocket/tree/master/Extensions">protocol extensions related * to the use of metadata. */ +@NonNullApi package io.rsocket.metadata; + +import reactor.util.annotation.NonNullApi; diff --git a/rsocket-core/src/main/java/io/rsocket/package-info.java b/rsocket-core/src/main/java/io/rsocket/package-info.java index 878a56301..6fe74fb38 100644 --- a/rsocket-core/src/main/java/io/rsocket/package-info.java +++ b/rsocket-core/src/main/java/io/rsocket/package-info.java @@ -23,4 +23,7 @@ *

To connect to or start a server see {@link io.rsocket.core.RSocketConnector RSocketConnector} * and {@link io.rsocket.core.RSocketServer RSocketServer} in {@link io.rsocket.core}. */ +@NonNullApi package io.rsocket; + +import reactor.util.annotation.NonNullApi; diff --git a/rsocket-core/src/main/java/io/rsocket/plugins/package-info.java b/rsocket-core/src/main/java/io/rsocket/plugins/package-info.java index 743e3a8a4..fd9e1f01a 100644 --- a/rsocket-core/src/main/java/io/rsocket/plugins/package-info.java +++ b/rsocket-core/src/main/java/io/rsocket/plugins/package-info.java @@ -15,4 +15,7 @@ */ /** Contracts for interception of transports, connections, and requests in in RSocket Java. */ +@NonNullApi package io.rsocket.plugins; + +import reactor.util.annotation.NonNullApi; diff --git a/rsocket-core/src/main/java/io/rsocket/resume/SessionManager.java b/rsocket-core/src/main/java/io/rsocket/resume/SessionManager.java index 3882103a0..1d5c23bd6 100644 --- a/rsocket-core/src/main/java/io/rsocket/resume/SessionManager.java +++ b/rsocket-core/src/main/java/io/rsocket/resume/SessionManager.java @@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import javax.annotation.Nullable; +import reactor.util.annotation.Nullable; public class SessionManager { private volatile boolean isDisposed; diff --git a/rsocket-core/src/main/java/io/rsocket/resume/package-info.java b/rsocket-core/src/main/java/io/rsocket/resume/package-info.java index aaaa3ee9f..98744386a 100644 --- a/rsocket-core/src/main/java/io/rsocket/resume/package-info.java +++ b/rsocket-core/src/main/java/io/rsocket/resume/package-info.java @@ -21,5 +21,7 @@ * href="https://github.com/rsocket/rsocket/blob/master/Protocol.md#resuming-operation">Resuming * Operation */ -@javax.annotation.ParametersAreNonnullByDefault +@NonNullApi package io.rsocket.resume; + +import reactor.util.annotation.NonNullApi; diff --git a/rsocket-core/src/main/java/io/rsocket/transport/package-info.java b/rsocket-core/src/main/java/io/rsocket/transport/package-info.java index 153676324..00536122a 100644 --- a/rsocket-core/src/main/java/io/rsocket/transport/package-info.java +++ b/rsocket-core/src/main/java/io/rsocket/transport/package-info.java @@ -15,5 +15,7 @@ */ /** Client and server transport contracts for pluggable transports. */ -@javax.annotation.ParametersAreNonnullByDefault +@NonNullApi package io.rsocket.transport; + +import reactor.util.annotation.NonNullApi; diff --git a/rsocket-core/src/main/java/io/rsocket/util/ByteBufPayload.java b/rsocket-core/src/main/java/io/rsocket/util/ByteBufPayload.java index f5d747f7f..4cf33fa86 100644 --- a/rsocket-core/src/main/java/io/rsocket/util/ByteBufPayload.java +++ b/rsocket-core/src/main/java/io/rsocket/util/ByteBufPayload.java @@ -28,7 +28,7 @@ import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; -import javax.annotation.Nullable; +import reactor.util.annotation.Nullable; public final class ByteBufPayload extends AbstractReferenceCounted implements Payload { private static final Recycler RECYCLER = diff --git a/rsocket-core/src/main/java/io/rsocket/util/DefaultPayload.java b/rsocket-core/src/main/java/io/rsocket/util/DefaultPayload.java index ec73399f1..58f282110 100644 --- a/rsocket-core/src/main/java/io/rsocket/util/DefaultPayload.java +++ b/rsocket-core/src/main/java/io/rsocket/util/DefaultPayload.java @@ -23,7 +23,7 @@ import java.nio.CharBuffer; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; -import javax.annotation.Nullable; +import reactor.util.annotation.Nullable; /** * An implementation of {@link Payload}. This implementation is not thread-safe, and hence diff --git a/rsocket-core/src/main/java/io/rsocket/util/package-info.java b/rsocket-core/src/main/java/io/rsocket/util/package-info.java index e034672f1..2fac3327f 100644 --- a/rsocket-core/src/main/java/io/rsocket/util/package-info.java +++ b/rsocket-core/src/main/java/io/rsocket/util/package-info.java @@ -15,5 +15,7 @@ */ /** Shared utility classes and {@link io.rsocket.Payload} implementations. */ -@javax.annotation.ParametersAreNonnullByDefault +@NonNullApi package io.rsocket.util; + +import reactor.util.annotation.NonNullApi; diff --git a/rsocket-core/src/test/java/io/rsocket/core/ConnectionSetupPayloadTest.java b/rsocket-core/src/test/java/io/rsocket/core/ConnectionSetupPayloadTest.java index 9d8b8354a..8eb5dee09 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/ConnectionSetupPayloadTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/ConnectionSetupPayloadTest.java @@ -82,7 +82,7 @@ private static ByteBuf encodeSetupFrame(boolean leaseEnabled, Payload setupPaylo leaseEnabled, KEEP_ALIVE_INTERVAL, KEEP_ALIVE_MAX_LIFETIME, - null, + Unpooled.EMPTY_BUFFER, METADATA_TYPE, DATA_TYPE, setupPayload); diff --git a/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterSubscribersTest.java b/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterSubscribersTest.java index 6f1ecf98b..00f74152a 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterSubscribersTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterSubscribersTest.java @@ -143,6 +143,6 @@ static Stream>> allInteractions() { rSocket -> rSocket.requestResponse(DefaultPayload.create("test")), rSocket -> rSocket.requestStream(DefaultPayload.create("test")), // rSocket -> rSocket.requestChannel(Mono.just(DefaultPayload.create("test"))), - rSocket -> rSocket.metadataPush(DefaultPayload.create("test"))); + rSocket -> rSocket.metadataPush(DefaultPayload.create("", "test"))); } } diff --git a/rsocket-core/src/test/java/io/rsocket/frame/LeaseFrameCodecTest.java b/rsocket-core/src/test/java/io/rsocket/frame/LeaseFrameCodecTest.java index 448b5003b..73c3bde5e 100644 --- a/rsocket-core/src/test/java/io/rsocket/frame/LeaseFrameCodecTest.java +++ b/rsocket-core/src/test/java/io/rsocket/frame/LeaseFrameCodecTest.java @@ -32,7 +32,7 @@ void leaseAbsentMetadata() { Assertions.assertFalse(FrameHeaderCodec.hasMetadata(lease)); Assertions.assertEquals(ttl, LeaseFrameCodec.ttl(lease)); Assertions.assertEquals(numRequests, LeaseFrameCodec.numRequests(lease)); - Assertions.assertEquals(0, LeaseFrameCodec.metadata(lease).readableBytes()); + Assertions.assertNull(LeaseFrameCodec.metadata(lease)); lease.release(); } diff --git a/rsocket-core/src/test/java/io/rsocket/frame/SetupFrameCodecTest.java b/rsocket-core/src/test/java/io/rsocket/frame/SetupFrameCodecTest.java index f7d649972..9607ad327 100644 --- a/rsocket-core/src/test/java/io/rsocket/frame/SetupFrameCodecTest.java +++ b/rsocket-core/src/test/java/io/rsocket/frame/SetupFrameCodecTest.java @@ -22,7 +22,7 @@ void testEncodingNoResume() { assertEquals(FrameType.SETUP, FrameHeaderCodec.frameType(frame)); assertFalse(SetupFrameCodec.resumeEnabled(frame)); - assertNull(SetupFrameCodec.resumeToken(frame)); + assertEquals(0, SetupFrameCodec.resumeToken(frame).readableBytes()); assertEquals("metadata_type", SetupFrameCodec.metadataMimeType(frame)); assertEquals("data_type", SetupFrameCodec.dataMimeType(frame)); assertEquals(metadata, SetupFrameCodec.metadata(frame)); diff --git a/rsocket-load-balancer/src/main/java/io/rsocket/client/filter/package-info.java b/rsocket-load-balancer/src/main/java/io/rsocket/client/filter/package-info.java new file mode 100644 index 000000000..55ce5646c --- /dev/null +++ b/rsocket-load-balancer/src/main/java/io/rsocket/client/filter/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2015-2020 the original author or authors. + * + * Licensed 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. + */ + +@NonNullApi +package io.rsocket.client.filter; + +import reactor.util.annotation.NonNullApi; diff --git a/rsocket-load-balancer/src/main/java/io/rsocket/client/package-info.java b/rsocket-load-balancer/src/main/java/io/rsocket/client/package-info.java new file mode 100644 index 000000000..ec21dee96 --- /dev/null +++ b/rsocket-load-balancer/src/main/java/io/rsocket/client/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2015-2020 the original author or authors. + * + * Licensed 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. + */ + +@NonNullApi +package io.rsocket.client; + +import reactor.util.annotation.NonNullApi; diff --git a/rsocket-load-balancer/src/main/java/io/rsocket/stat/package-info.java b/rsocket-load-balancer/src/main/java/io/rsocket/stat/package-info.java new file mode 100644 index 000000000..cfb071175 --- /dev/null +++ b/rsocket-load-balancer/src/main/java/io/rsocket/stat/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2015-2020 the original author or authors. + * + * Licensed 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. + */ + +@NonNullApi +package io.rsocket.stat; + +import reactor.util.annotation.NonNullApi; diff --git a/rsocket-micrometer/build.gradle b/rsocket-micrometer/build.gradle index 5f2aeb16f..4be616623 100644 --- a/rsocket-micrometer/build.gradle +++ b/rsocket-micrometer/build.gradle @@ -27,8 +27,6 @@ dependencies { implementation 'org.slf4j:slf4j-api' - compileOnly 'com.google.code.findbugs:jsr305' - testImplementation project(':rsocket-test') testImplementation 'io.projectreactor:reactor-test' testImplementation 'org.assertj:assertj-core' diff --git a/rsocket-test/build.gradle b/rsocket-test/build.gradle index 3009b5135..5ec1a8061 100644 --- a/rsocket-test/build.gradle +++ b/rsocket-test/build.gradle @@ -26,8 +26,6 @@ dependencies { api 'org.hdrhistogram:HdrHistogram' api 'org.junit.jupiter:junit-jupiter-api' - compileOnly 'com.google.code.findbugs:jsr305' - implementation 'io.projectreactor:reactor-test' implementation 'org.assertj:assertj-core' implementation 'org.mockito:mockito-core' diff --git a/rsocket-transport-local/build.gradle b/rsocket-transport-local/build.gradle index 8c3226065..a5ba84d5c 100644 --- a/rsocket-transport-local/build.gradle +++ b/rsocket-transport-local/build.gradle @@ -24,8 +24,6 @@ plugins { dependencies { api project(':rsocket-core') - compileOnly 'com.google.code.findbugs:jsr305' - testImplementation project(':rsocket-test') testImplementation 'io.projectreactor:reactor-test' testImplementation 'org.assertj:assertj-core' diff --git a/rsocket-transport-netty/build.gradle b/rsocket-transport-netty/build.gradle index 0aac12d5c..64e483c90 100644 --- a/rsocket-transport-netty/build.gradle +++ b/rsocket-transport-netty/build.gradle @@ -32,8 +32,6 @@ dependencies { api 'io.projectreactor.netty:reactor-netty' api 'org.slf4j:slf4j-api' - compileOnly 'com.google.code.findbugs:jsr305' - testImplementation project(':rsocket-test') testImplementation 'io.projectreactor:reactor-test' testImplementation 'org.assertj:assertj-core' diff --git a/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/client/TcpClientTransport.java b/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/client/TcpClientTransport.java index 8be019f1c..22f139310 100644 --- a/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/client/TcpClientTransport.java +++ b/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/client/TcpClientTransport.java @@ -75,7 +75,7 @@ public static TcpClientTransport create(String bindAddress, int port) { public static TcpClientTransport create(InetSocketAddress address) { Objects.requireNonNull(address, "address must not be null"); - TcpClient tcpClient = TcpClient.create().addressSupplier(() -> address); + TcpClient tcpClient = TcpClient.create().remoteAddress(() -> address); return create(tcpClient); } diff --git a/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/client/WebsocketClientTransport.java b/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/client/WebsocketClientTransport.java index 6991728ca..747401210 100644 --- a/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/client/WebsocketClientTransport.java +++ b/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/client/WebsocketClientTransport.java @@ -35,6 +35,7 @@ import java.util.function.Supplier; import reactor.core.publisher.Mono; import reactor.netty.http.client.HttpClient; +import reactor.netty.http.client.WebsocketClientSpec; import reactor.netty.tcp.TcpClient; /** @@ -47,7 +48,7 @@ public final class WebsocketClientTransport implements ClientTransport, Transpor private final HttpClient client; - private String path; + private final String path; private Supplier> transportHeaders = Collections::emptyMap; @@ -92,7 +93,7 @@ public static WebsocketClientTransport create(String bindAddress, int port) { public static WebsocketClientTransport create(InetSocketAddress address) { Objects.requireNonNull(address, "address must not be null"); - TcpClient client = TcpClient.create().addressSupplier(() -> address); + TcpClient client = TcpClient.create().remoteAddress(() -> address); return create(client); } @@ -155,7 +156,8 @@ public Mono connect(int mtu) { ? isError : client .headers(headers -> transportHeaders.get().forEach(headers::set)) - .websocket(FRAME_LENGTH_MASK) + .websocket( + WebsocketClientSpec.builder().maxFramePayloadLength(FRAME_LENGTH_MASK).build()) .uri(path) .connect() .map( diff --git a/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/server/CloseableChannel.java b/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/server/CloseableChannel.java index f6e83bc36..c0340c7a2 100644 --- a/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/server/CloseableChannel.java +++ b/rsocket-transport-netty/src/main/java/io/rsocket/transport/netty/server/CloseableChannel.java @@ -28,7 +28,7 @@ */ public final class CloseableChannel implements Closeable { - private DisposableChannel channel; + private final DisposableChannel channel; /** * Creates a new instance diff --git a/rsocket-transport-netty/src/test/java/io/rsocket/transport/netty/TcpSecureTransportTest.java b/rsocket-transport-netty/src/test/java/io/rsocket/transport/netty/TcpSecureTransportTest.java index b77de6d4e..95bebd6aa 100644 --- a/rsocket-transport-netty/src/test/java/io/rsocket/transport/netty/TcpSecureTransportTest.java +++ b/rsocket-transport-netty/src/test/java/io/rsocket/transport/netty/TcpSecureTransportTest.java @@ -20,7 +20,7 @@ public class TcpSecureTransportTest implements TransportTest { (address, server) -> TcpClientTransport.create( TcpClient.create() - .addressSupplier(server::address) + .remoteAddress(server::address) .secure( ssl -> ssl.sslContext( @@ -31,7 +31,7 @@ public class TcpSecureTransportTest implements TransportTest { SelfSignedCertificate ssc = new SelfSignedCertificate(); TcpServer server = TcpServer.create() - .addressSupplier(() -> address) + .bindAddress(() -> address) .secure( ssl -> ssl.sslContext( diff --git a/rsocket-transport-netty/src/test/java/io/rsocket/transport/netty/WebsocketSecureTransportTest.java b/rsocket-transport-netty/src/test/java/io/rsocket/transport/netty/WebsocketSecureTransportTest.java index c1d608979..ec33060b2 100644 --- a/rsocket-transport-netty/src/test/java/io/rsocket/transport/netty/WebsocketSecureTransportTest.java +++ b/rsocket-transport-netty/src/test/java/io/rsocket/transport/netty/WebsocketSecureTransportTest.java @@ -38,7 +38,7 @@ final class WebsocketSecureTransportTest implements TransportTest { (address, server) -> WebsocketClientTransport.create( HttpClient.create() - .addressSupplier(server::address) + .remoteAddress(server::address) .secure( ssl -> ssl.sslContext( @@ -53,7 +53,7 @@ final class WebsocketSecureTransportTest implements TransportTest { HttpServer server = HttpServer.from( TcpServer.create() - .addressSupplier(() -> address) + .bindAddress(() -> address) .secure( ssl -> ssl.sslContext( From fdc9b1bc50cedbb49366c20cf639959e55c0c75a Mon Sep 17 00:00:00 2001 From: Oleh Dokuka Date: Sun, 10 May 2020 23:34:59 +0300 Subject: [PATCH 18/25] removes limit rate operator (#829) --- .../io/rsocket/core/RSocketRequester.java | 1 - .../io/rsocket/core/RSocketResponder.java | 6 +- .../plugins/LimitRateInterceptorExample.java | 168 ++++++++++++++++++ .../java/io/rsocket/test/TransportTest.java | 3 +- 4 files changed, 170 insertions(+), 8 deletions(-) create mode 100644 rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/plugins/LimitRateInterceptorExample.java diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java index 068797d39..3de074953 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java @@ -491,7 +491,6 @@ void hookOnFirstRequest(long n) { receivers.put(streamId, receiver); inboundFlux - .limitRate(Queues.SMALL_BUFFER_SIZE) .doOnDiscard(ReferenceCounted.class, DROPPED_ELEMENTS_CONSUMER) .subscribe(upstreamSubscriber); diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java index dce182b49..d5f9206d8 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java @@ -47,7 +47,6 @@ import reactor.core.Exceptions; import reactor.core.publisher.*; import reactor.util.annotation.Nullable; -import reactor.util.concurrent.Queues; /** Responder side of RSocket. Receives {@link ByteBuf}s from a peer's {@link RSocketRequester} */ class RSocketResponder implements RSocket { @@ -526,10 +525,7 @@ protected void hookFinally(SignalType type) { }; sendingSubscriptions.put(streamId, subscriber); - response - .limitRate(Queues.SMALL_BUFFER_SIZE) - .doOnDiscard(ReferenceCounted.class, DROPPED_ELEMENTS_CONSUMER) - .subscribe(subscriber); + response.doOnDiscard(ReferenceCounted.class, DROPPED_ELEMENTS_CONSUMER).subscribe(subscriber); } private void handleChannel(int streamId, Payload payload, long initialRequestN) { diff --git a/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/plugins/LimitRateInterceptorExample.java b/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/plugins/LimitRateInterceptorExample.java new file mode 100644 index 000000000..ac473d7b1 --- /dev/null +++ b/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/plugins/LimitRateInterceptorExample.java @@ -0,0 +1,168 @@ +package io.rsocket.examples.transport.tcp.plugins; + +import io.rsocket.Payload; +import io.rsocket.RSocket; +import io.rsocket.SocketAcceptor; +import io.rsocket.core.RSocketConnector; +import io.rsocket.core.RSocketServer; +import io.rsocket.examples.transport.tcp.stream.StreamingClient; +import io.rsocket.plugins.RSocketInterceptor; +import io.rsocket.transport.netty.client.TcpClientTransport; +import io.rsocket.transport.netty.server.TcpServerTransport; +import io.rsocket.util.DefaultPayload; +import io.rsocket.util.RSocketProxy; +import java.time.Duration; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import org.reactivestreams.Publisher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; +import reactor.util.concurrent.Queues; + +public class LimitRateInterceptorExample { + + private static final Logger logger = LoggerFactory.getLogger(StreamingClient.class); + + public static void main(String[] args) { + BlockingQueue requests = new ArrayBlockingQueue<>(100); + RSocketServer.create( + SocketAcceptor.with( + new RSocket() { + @Override + public Flux requestStream(Payload payload) { + return Flux.interval(Duration.ofMillis(100)) + .doOnRequest(e -> requests.add("Responder requestN(" + e + ")")) + .map(aLong -> DefaultPayload.create("Interval: " + aLong)); + } + + @Override + public Flux requestChannel(Publisher payloads) { + return Flux.from(payloads) + .doOnRequest(e -> requests.add("Responder requestN(" + e + ")")); + } + })) + .interceptors( + ir -> + ir.forRequester(LimitRateInterceptor.forRequester()) + .forResponder(LimitRateInterceptor.forResponder())) + .bind(TcpServerTransport.create("localhost", 7000)) + .subscribe(); + + RSocket socket = + RSocketConnector.create() + .interceptors( + ir -> + ir.forRequester(LimitRateInterceptor.forRequester()) + .forResponder(LimitRateInterceptor.forResponder())) + .connect(TcpClientTransport.create("localhost", 7000)) + .block(); + + socket + .requestStream(DefaultPayload.create("Hello")) + .doOnRequest(e -> requests.add("Requester requestN(" + e + ")")) + .map(Payload::getDataUtf8) + .doOnNext(logger::debug) + .take(10) + .then() + .block(); + + requests.forEach(request -> logger.debug("Requested : {}", request)); + requests.clear(); + + logger.debug("-----------------------------------------------------------------"); + logger.debug("Does requestChannel"); + socket + .requestChannel( + Flux.generate( + () -> 1L, + (s, sink) -> { + sink.next(DefaultPayload.create("Next " + s)); + return ++s; + }) + .doOnRequest(e -> requests.add("Requester Upstream requestN(" + e + ")"))) + .doOnRequest(e -> requests.add("Requester Downstream requestN(" + e + ")")) + .map(Payload::getDataUtf8) + .doOnNext(logger::debug) + .take(10) + .then() + .doFinally(signalType -> socket.dispose()) + .then() + .block(); + + requests.forEach(request -> logger.debug("Requested : {}", request)); + } + + static class LimitRateInterceptor implements RSocketInterceptor { + + final boolean requesterSide; + final int highTide; + final int lowTide; + + LimitRateInterceptor(boolean requesterSide, int highTide, int lowTide) { + this.requesterSide = requesterSide; + this.highTide = highTide; + this.lowTide = lowTide; + } + + @Override + public RSocket apply(RSocket socket) { + return new LimitRateRSocket(socket, requesterSide, highTide, lowTide); + } + + public static LimitRateInterceptor forRequester() { + return forRequester(Queues.SMALL_BUFFER_SIZE); + } + + public static LimitRateInterceptor forRequester(int limit) { + return forRequester(limit, limit); + } + + public static LimitRateInterceptor forRequester(int highTide, int lowTide) { + return new LimitRateInterceptor(true, highTide, lowTide); + } + + public static LimitRateInterceptor forResponder() { + return forRequester(Queues.SMALL_BUFFER_SIZE); + } + + public static LimitRateInterceptor forResponder(int limit) { + return forRequester(limit, limit); + } + + public static LimitRateInterceptor forResponder(int highTide, int lowTide) { + return new LimitRateInterceptor(false, highTide, lowTide); + } + } + + static class LimitRateRSocket extends RSocketProxy { + + final boolean requesterSide; + final int highTide; + final int lowTide; + + public LimitRateRSocket(RSocket source, boolean requesterSide, int highTide, int lowTide) { + super(source); + this.requesterSide = requesterSide; + this.highTide = highTide; + this.lowTide = lowTide; + } + + @Override + public Flux requestStream(Payload payload) { + Flux flux = super.requestStream(payload); + if (requesterSide) { + return flux; + } + return flux.limitRate(highTide, lowTide); + } + + @Override + public Flux requestChannel(Publisher payloads) { + if (requesterSide) { + return super.requestChannel(Flux.from(payloads).limitRate(highTide, lowTide)); + } + return super.requestChannel(payloads).limitRate(highTide, lowTide); + } + } +} diff --git a/rsocket-test/src/main/java/io/rsocket/test/TransportTest.java b/rsocket-test/src/main/java/io/rsocket/test/TransportTest.java index 583f58634..fc059c7d1 100644 --- a/rsocket-test/src/main/java/io/rsocket/test/TransportTest.java +++ b/rsocket-test/src/main/java/io/rsocket/test/TransportTest.java @@ -237,8 +237,7 @@ default void requestChannel3() { .expectComplete() .verify(getTimeout()); - Assertions.assertThat(requested.get()) - .isEqualTo(256L); // 256 because of eager behavior of limitRate + Assertions.assertThat(requested.get()).isEqualTo(3L); } @DisplayName("makes 1 requestChannel request with 512 payloads") From 69ca8185920d60ef4f20b41db0c19b330bae7330 Mon Sep 17 00:00:00 2001 From: Oleh Dokuka Date: Sun, 10 May 2020 23:35:41 +0300 Subject: [PATCH 19/25] provides `bindNow` shortcut for the server (#830) --- .../src/main/java/io/rsocket/core/RSocketServer.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java index 66e2249b5..a0f7c810b 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java @@ -290,6 +290,14 @@ public Mono get() { }); } + /** + * Start the server on the given transport. Effectively is a shortcut for {@code + * .bind(ServerTransport).block()} + */ + public T bindNow(ServerTransport transport) { + return bind(transport).block(); + } + /** * An alternative to {@link #bind(ServerTransport)} that is useful for installing RSocket on a * server that is started independently. From 31c1509f9a31c006cb9635d78e54dd0924377614 Mon Sep 17 00:00:00 2001 From: Oleh Dokuka Date: Mon, 11 May 2020 15:31:52 +0300 Subject: [PATCH 20/25] removes deprecated errorConsumer (#832) --- .../main/java/io/rsocket/RSocketFactory.java | 20 ++-- .../io/rsocket/core/RSocketConnector.java | 16 ---- .../io/rsocket/core/RSocketRequester.java | 38 ++++---- .../io/rsocket/core/RSocketResponder.java | 27 +++--- .../java/io/rsocket/core/RSocketServer.java | 20 +--- .../ClientServerInputMultiplexer.java | 5 +- .../rsocket/lease/ResponderLeaseHandler.java | 6 +- .../io/rsocket/core/AbstractSocketRule.java | 10 -- .../java/io/rsocket/core/KeepAliveTest.java | 55 ++--------- .../io/rsocket/core/RSocketLeaseTest.java | 4 +- .../core/RSocketRequesterSubscribersTest.java | 1 - .../io/rsocket/core/RSocketRequesterTest.java | 25 ++--- .../io/rsocket/core/RSocketResponderTest.java | 17 +--- .../java/io/rsocket/core/RSocketTest.java | 93 ++++--------------- .../io/rsocket/core/SetupRejectionTest.java | 6 -- 15 files changed, 90 insertions(+), 253 deletions(-) diff --git a/rsocket-core/src/main/java/io/rsocket/RSocketFactory.java b/rsocket-core/src/main/java/io/rsocket/RSocketFactory.java index 178cc4fa9..e23bcceb2 100644 --- a/rsocket-core/src/main/java/io/rsocket/RSocketFactory.java +++ b/rsocket-core/src/main/java/io/rsocket/RSocketFactory.java @@ -111,7 +111,7 @@ public static class ClientRSocketFactory implements ClientTransportAcceptor { private Resume resume; public ClientRSocketFactory() { - this(RSocketConnector.create().errorConsumer(Throwable::printStackTrace)); + this(RSocketConnector.create()); } public ClientRSocketFactory(RSocketConnector connector) { @@ -393,9 +393,13 @@ public ClientRSocketFactory fragment(int mtu) { return this; } - /** @deprecated this is deprecated with no replacement. */ + /** + * @deprecated this handler is deliberately no-ops and is deprecated with no replacement. In + * order to observe errors, it is recommended to add error handler using {@code doOnError} + * on the specific logical stream. In order to observe connection, or RSocket terminal + * errors, it is recommended to hook on {@link Closeable#onClose()} handler. + */ public ClientRSocketFactory errorConsumer(Consumer errorConsumer) { - connector.errorConsumer(errorConsumer); return this; } @@ -417,7 +421,7 @@ public static class ServerRSocketFactory implements ServerTransportAcceptor { private Resume resume; public ServerRSocketFactory() { - this(RSocketServer.create().errorConsumer(Throwable::printStackTrace)); + this(RSocketServer.create()); } public ServerRSocketFactory(RSocketServer server) { @@ -497,9 +501,13 @@ public ServerRSocketFactory fragment(int mtu) { return this; } - /** @deprecated this is deprecated with no replacement. */ + /** + * @deprecated this handler is deliberately no-ops and is deprecated with no replacement. In + * order to observe errors, it is recommended to add error handler using {@code doOnError} + * on the specific logical stream. In order to observe connection, or RSocket terminal + * errors, it is recommended to hook on {@link Closeable#onClose()} handler. + */ public ServerRSocketFactory errorConsumer(Consumer errorConsumer) { - server.errorConsumer(errorConsumer); return this; } diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java index 38393c27d..d9622e0f0 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java @@ -91,8 +91,6 @@ public class RSocketConnector { private int mtu = 0; private PayloadDecoder payloadDecoder = PayloadDecoder.DEFAULT; - private Consumer errorConsumer = ex -> {}; - private RSocketConnector() {} /** @@ -436,17 +434,6 @@ public RSocketConnector payloadDecoder(PayloadDecoder decoder) { return this; } - /** - * @deprecated this is deprecated with no replacement and will be removed after {@link - * io.rsocket.RSocketFactory} is removed. - */ - @Deprecated - public RSocketConnector errorConsumer(Consumer errorConsumer) { - Objects.requireNonNull(errorConsumer); - this.errorConsumer = errorConsumer; - return this; - } - /** * The final step to connect with the transport to use as input and the resulting {@code * Mono} as output. Each subscriber to the returned {@code Mono} starts a new connection @@ -524,7 +511,6 @@ public Mono connect(Supplier transportSupplier) { new RSocketRequester( multiplexer.asClientConnection(), payloadDecoder, - errorConsumer, StreamIdSupplier.clientSupplier(), mtu, (int) keepAliveInterval.toMillis(), @@ -564,7 +550,6 @@ public Mono connect(Supplier transportSupplier) { CLIENT_TAG, wrappedConnection.alloc(), leases.sender(), - errorConsumer, leases.stats()) : ResponderLeaseHandler.None; @@ -573,7 +558,6 @@ public Mono connect(Supplier transportSupplier) { multiplexer.asServerConnection(), wrappedRSocketHandler, payloadDecoder, - errorConsumer, responderLeaseHandler, mtu); diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java index 3de074953..cdfda0755 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java @@ -59,6 +59,8 @@ import org.reactivestreams.Publisher; import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import reactor.core.publisher.BaseSubscriber; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -74,9 +76,8 @@ * Requester Side of a RSocket socket. Sends {@link ByteBuf}s to a {@link RSocketResponder} of peer */ class RSocketRequester implements RSocket { - private static final AtomicReferenceFieldUpdater TERMINATION_ERROR = - AtomicReferenceFieldUpdater.newUpdater( - RSocketRequester.class, Throwable.class, "terminationError"); + private static final Logger LOGGER = LoggerFactory.getLogger(RSocketRequester.class); + private static final Exception CLOSED_CHANNEL_EXCEPTION = new ClosedChannelException(); private static final Consumer DROPPED_ELEMENTS_CONSUMER = referenceCounted -> { @@ -93,9 +94,14 @@ class RSocketRequester implements RSocket { CLOSED_CHANNEL_EXCEPTION.setStackTrace(new StackTraceElement[0]); } + private volatile Throwable terminationError; + + private static final AtomicReferenceFieldUpdater TERMINATION_ERROR = + AtomicReferenceFieldUpdater.newUpdater( + RSocketRequester.class, Throwable.class, "terminationError"); + private final DuplexConnection connection; private final PayloadDecoder payloadDecoder; - private final Consumer errorConsumer; private final StreamIdSupplier streamIdSupplier; private final IntObjectMap senders; private final IntObjectMap> receivers; @@ -104,14 +110,12 @@ class RSocketRequester implements RSocket { private final RequesterLeaseHandler leaseHandler; private final ByteBufAllocator allocator; private final KeepAliveFramesAcceptor keepAliveFramesAcceptor; - private volatile Throwable terminationError; private final MonoProcessor onClose; private final Scheduler serialScheduler; RSocketRequester( DuplexConnection connection, PayloadDecoder payloadDecoder, - Consumer errorConsumer, StreamIdSupplier streamIdSupplier, int mtu, int keepAliveTickPeriod, @@ -122,7 +126,6 @@ class RSocketRequester implements RSocket { this.connection = connection; this.allocator = connection.alloc(); this.payloadDecoder = payloadDecoder; - this.errorConsumer = errorConsumer; this.streamIdSupplier = streamIdSupplier; this.mtu = mtu; this.leaseHandler = leaseHandler; @@ -140,7 +143,7 @@ class RSocketRequester implements RSocket { .subscribe(null, this::tryTerminateOnConnectionError, this::tryTerminateOnConnectionClose); connection.send(sendProcessor).subscribe(null, this::handleSendProcessorError); - connection.receive().subscribe(this::handleIncomingFrames, errorConsumer); + connection.receive().subscribe(this::handleIncomingFrames, e -> {}); if (keepAliveTickPeriod != 0 && keepAliveHandler != null) { KeepAliveSupport keepAliveSupport = @@ -396,7 +399,6 @@ private Flux handleChannel(Flux request) { payload.release(); final IllegalArgumentException t = new IllegalArgumentException(INVALID_PAYLOAD_ERROR_MESSAGE); - errorConsumer.accept(t); return Mono.error(t); } return handleChannel(payload, flux); @@ -446,7 +448,6 @@ protected void hookOnNext(Payload payload) { cancel(); final IllegalArgumentException t = new IllegalArgumentException(INVALID_PAYLOAD_ERROR_MESSAGE); - errorConsumer.accept(t); // no need to send any errors. sendProcessor.onNext(CancelFrameCodec.encode(allocator, streamId)); receiver.onError(t); @@ -609,9 +610,9 @@ private void handleStreamZero(FrameType type, ByteBuf frame) { break; default: // Ignore unknown frames. Throwing an error will close the socket. - errorConsumer.accept( - new IllegalStateException( - "Client received supported frame on stream 0: " + frame.toString())); + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Requester received unsupported frame on stream 0: " + frame.toString()); + } } } @@ -668,7 +669,7 @@ private void handleFrame(int streamId, FrameType type, ByteBuf frame) { } default: throw new IllegalStateException( - "Client received supported frame on stream " + streamId + ": " + frame.toString()); + "Requester received unsupported frame on stream " + streamId + ": " + frame.toString()); } } @@ -736,7 +737,9 @@ private void terminate(Throwable e) { try { receiver.onError(e); } catch (Throwable t) { - errorConsumer.accept(t); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Dropped exception", t); + } } }); } @@ -748,14 +751,15 @@ private void terminate(Throwable e) { try { sender.cancel(); } catch (Throwable t) { - errorConsumer.accept(t); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Dropped exception", t); + } } }); } senders.clear(); receivers.clear(); sendProcessor.dispose(); - errorConsumer.accept(e); onClose.onError(e); } diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java index d5f9206d8..ca5e605c7 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java @@ -43,6 +43,8 @@ import org.reactivestreams.Publisher; import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import reactor.core.Disposable; import reactor.core.Exceptions; import reactor.core.publisher.*; @@ -50,6 +52,8 @@ /** Responder side of RSocket. Receives {@link ByteBuf}s from a peer's {@link RSocketRequester} */ class RSocketResponder implements RSocket { + private static final Logger LOGGER = LoggerFactory.getLogger(RSocketResponder.class); + private static final Consumer DROPPED_ELEMENTS_CONSUMER = referenceCounted -> { if (referenceCounted.refCnt() > 0) { @@ -69,7 +73,6 @@ class RSocketResponder implements RSocket { private final io.rsocket.ResponderRSocket responderRSocket; private final PayloadDecoder payloadDecoder; - private final Consumer errorConsumer; private final ResponderLeaseHandler leaseHandler; private final Disposable leaseHandlerDisposable; private final MonoProcessor onClose; @@ -87,12 +90,10 @@ class RSocketResponder implements RSocket { private final UnboundedProcessor sendProcessor; private final ByteBufAllocator allocator; - @SuppressWarnings("deprecation") RSocketResponder( DuplexConnection connection, RSocket requestHandler, PayloadDecoder payloadDecoder, - Consumer errorConsumer, ResponderLeaseHandler leaseHandler, int mtu) { this.connection = connection; @@ -106,7 +107,6 @@ class RSocketResponder implements RSocket { : null; this.payloadDecoder = payloadDecoder; - this.errorConsumer = errorConsumer; this.leaseHandler = leaseHandler; this.sendingSubscriptions = new SynchronizedIntObjectHashMap<>(); this.channelProcessors = new SynchronizedIntObjectHashMap<>(); @@ -118,7 +118,7 @@ class RSocketResponder implements RSocket { connection.send(sendProcessor).subscribe(null, this::handleSendProcessorError); - connection.receive().subscribe(this::handleFrame, errorConsumer); + connection.receive().subscribe(this::handleFrame, e -> {}); leaseHandlerDisposable = leaseHandler.send(sendProcessor::onNextPrioritized); this.connection @@ -135,7 +135,9 @@ private void handleSendProcessorError(Throwable t) { try { subscription.cancel(); } catch (Throwable e) { - errorConsumer.accept(e); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Dropped exception", t); + } } }); @@ -146,7 +148,9 @@ private void handleSendProcessorError(Throwable t) { try { subscription.onError(t); } catch (Throwable e) { - errorConsumer.accept(e); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Dropped exception", t); + } } }); } @@ -375,9 +379,7 @@ protected void hookOnSubscribe(Subscription subscription) { } @Override - protected void hookOnError(Throwable throwable) { - errorConsumer.accept(throwable); - } + protected void hookOnError(Throwable throwable) {} @Override protected void hookFinally(SignalType type) { @@ -583,9 +585,7 @@ protected void hookOnSubscribe(Subscription subscription) { } @Override - protected void hookOnError(Throwable throwable) { - errorConsumer.accept(throwable); - } + protected void hookOnError(Throwable throwable) {} }); } @@ -599,7 +599,6 @@ private void handleCancelFrame(int streamId) { } private void handleError(int streamId, Throwable t) { - errorConsumer.accept(t); sendProcessor.onNext(ErrorFrameCodec.encode(allocator, streamId, t)); } diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java index a0f7c810b..6390d44dd 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java @@ -67,8 +67,6 @@ public final class RSocketServer { private int mtu = 0; private PayloadDecoder payloadDecoder = PayloadDecoder.DEFAULT; - private Consumer errorConsumer = ex -> {}; - private RSocketServer() {} /** Static factory method to create an {@code RSocketServer}. */ @@ -247,16 +245,6 @@ public RSocketServer payloadDecoder(PayloadDecoder decoder) { return this; } - /** - * @deprecated this is deprecated with no replacement and will be removed after {@link - * io.rsocket.RSocketFactory} is removed. - */ - @Deprecated - public RSocketServer errorConsumer(Consumer errorConsumer) { - this.errorConsumer = errorConsumer; - return this; - } - /** * Start the server on the given transport. * @@ -395,7 +383,6 @@ private Mono acceptSetup( new RSocketRequester( wrappedMultiplexer.asServerConnection(), payloadDecoder, - errorConsumer, StreamIdSupplier.serverSupplier(), mtu, setupPayload.keepAliveInterval(), @@ -422,11 +409,7 @@ private Mono acceptSetup( ResponderLeaseHandler responderLeaseHandler = leaseEnabled ? new ResponderLeaseHandler.Impl<>( - SERVER_TAG, - connection.alloc(), - leases.sender(), - errorConsumer, - leases.stats()) + SERVER_TAG, connection.alloc(), leases.sender(), leases.stats()) : ResponderLeaseHandler.None; RSocket rSocketResponder = @@ -434,7 +417,6 @@ private Mono acceptSetup( connection, wrappedRSocketHandler, payloadDecoder, - errorConsumer, responderLeaseHandler, mtu); }) diff --git a/rsocket-core/src/main/java/io/rsocket/internal/ClientServerInputMultiplexer.java b/rsocket-core/src/main/java/io/rsocket/internal/ClientServerInputMultiplexer.java index 0d24c51d8..038120efc 100644 --- a/rsocket-core/src/main/java/io/rsocket/internal/ClientServerInputMultiplexer.java +++ b/rsocket-core/src/main/java/io/rsocket/internal/ClientServerInputMultiplexer.java @@ -119,10 +119,7 @@ public ClientServerInputMultiplexer( break; } }, - t -> { - LOGGER.error("Error receiving frame:", t); - dispose(); - }); + t -> {}); } public DuplexConnection asClientServerConnection() { diff --git a/rsocket-core/src/main/java/io/rsocket/lease/ResponderLeaseHandler.java b/rsocket-core/src/main/java/io/rsocket/lease/ResponderLeaseHandler.java index 2035ade87..df8787cb7 100644 --- a/rsocket-core/src/main/java/io/rsocket/lease/ResponderLeaseHandler.java +++ b/rsocket-core/src/main/java/io/rsocket/lease/ResponderLeaseHandler.java @@ -41,7 +41,6 @@ final class Impl implements ResponderLeaseHandler { private final String tag; private final ByteBufAllocator allocator; private final Function, Flux> leaseSender; - private final Consumer errorConsumer; private final Optional leaseStatsOption; private final T leaseStats; @@ -49,12 +48,10 @@ public Impl( String tag, ByteBufAllocator allocator, Function, Flux> leaseSender, - Consumer errorConsumer, Optional leaseStatsOption) { this.tag = tag; this.allocator = allocator; this.leaseSender = leaseSender; - this.errorConsumer = errorConsumer; this.leaseStatsOption = leaseStatsOption; this.leaseStats = leaseStatsOption.orElse(null); } @@ -86,8 +83,7 @@ public Disposable send(Consumer leaseFrameSender) { lease -> { currentLease = create(lease); leaseFrameSender.accept(createLeaseFrame(lease)); - }, - errorConsumer); + }); } @Override diff --git a/rsocket-core/src/test/java/io/rsocket/core/AbstractSocketRule.java b/rsocket-core/src/test/java/io/rsocket/core/AbstractSocketRule.java index 20972a0d3..ac5832aaa 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/AbstractSocketRule.java +++ b/rsocket-core/src/test/java/io/rsocket/core/AbstractSocketRule.java @@ -21,8 +21,6 @@ import io.rsocket.buffer.LeaksTrackingByteBufAllocator; import io.rsocket.test.util.TestDuplexConnection; import io.rsocket.test.util.TestSubscriber; -import java.util.concurrent.ConcurrentLinkedQueue; -import org.junit.Assert; import org.junit.rules.ExternalResource; import org.junit.runner.Description; import org.junit.runners.model.Statement; @@ -33,7 +31,6 @@ public abstract class AbstractSocketRule extends ExternalReso protected TestDuplexConnection connection; protected Subscriber connectSub; protected T socket; - protected ConcurrentLinkedQueue errors; protected LeaksTrackingByteBufAllocator allocator; @Override @@ -44,7 +41,6 @@ public void evaluate() throws Throwable { allocator = LeaksTrackingByteBufAllocator.instrument(ByteBufAllocator.DEFAULT); connection = new TestDuplexConnection(allocator); connectSub = TestSubscriber.create(); - errors = new ConcurrentLinkedQueue<>(); init(); base.evaluate(); } @@ -57,12 +53,6 @@ protected void init() { protected abstract T newRSocket(); - public void assertNoConnectionErrors() { - if (errors.size() > 1) { - Assert.fail("No connection errors expected: " + errors.peek().toString()); - } - } - public ByteBufAllocator alloc() { return allocator; } diff --git a/rsocket-core/src/test/java/io/rsocket/core/KeepAliveTest.java b/rsocket-core/src/test/java/io/rsocket/core/KeepAliveTest.java index b3ded08ec..d98f86113 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/KeepAliveTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/KeepAliveTest.java @@ -35,9 +35,6 @@ import io.rsocket.test.util.TestDuplexConnection; import io.rsocket.util.DefaultPayload; import java.time.Duration; -import java.util.ArrayList; -import java.util.List; -import java.util.function.Consumer; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -57,12 +54,10 @@ static RSocketState requester(int tickPeriod, int timeout) { LeaksTrackingByteBufAllocator allocator = LeaksTrackingByteBufAllocator.instrument(ByteBufAllocator.DEFAULT); TestDuplexConnection connection = new TestDuplexConnection(allocator); - Errors errors = new Errors(); RSocketRequester rSocket = new RSocketRequester( connection, DefaultPayload::create, - errors, StreamIdSupplier.clientSupplier(), 0, tickPeriod, @@ -70,7 +65,7 @@ static RSocketState requester(int tickPeriod, int timeout) { new DefaultKeepAliveHandler(connection), RequesterLeaseHandler.None, TestScheduler.INSTANCE); - return new RSocketState(rSocket, errors, allocator, connection); + return new RSocketState(rSocket, allocator, connection); } static ResumableRSocketState resumableRequester(int tickPeriod, int timeout) { @@ -85,12 +80,10 @@ static ResumableRSocketState resumableRequester(int tickPeriod, int timeout) { Duration.ofSeconds(10), false); - Errors errors = new Errors(); RSocketRequester rSocket = new RSocketRequester( resumableConnection, DefaultPayload::create, - errors, StreamIdSupplier.clientSupplier(), 0, tickPeriod, @@ -98,7 +91,7 @@ static ResumableRSocketState resumableRequester(int tickPeriod, int timeout) { new ResumableKeepAliveHandler(resumableConnection), RequesterLeaseHandler.None, TestScheduler.INSTANCE); - return new ResumableRSocketState(rSocket, errors, connection, resumableConnection, allocator); + return new ResumableRSocketState(rSocket, connection, resumableConnection, allocator); } @BeforeEach @@ -121,10 +114,8 @@ void rSocketNotDisposedOnPresentKeepAlives() { Mono.delay(Duration.ofMillis(2000)).block(); RSocket rSocket = requesterState.rSocket(); - List errors = requesterState.errors().errors(); Assertions.assertThat(rSocket.isDisposed()).isFalse(); - Assertions.assertThat(errors).isEmpty(); } @Test @@ -143,11 +134,12 @@ void rSocketDisposedOnMissingKeepAlives() { Mono.delay(Duration.ofMillis(2000)).block(); - List errors = requesterState.errors().errors(); Assertions.assertThat(rSocket.isDisposed()).isTrue(); - Assertions.assertThat(errors).hasSize(1); - Throwable throwable = errors.get(0); - Assertions.assertThat(throwable).isInstanceOf(ConnectionErrorException.class); + rSocket + .onClose() + .as(StepVerifier::create) + .expectError(ConnectionErrorException.class) + .verify(Duration.ofMillis(100)); } @Test @@ -224,13 +216,11 @@ void resumableRequesterNoKeepAlivesAfterDispose() { @Test void resumableRSocketsNotDisposedOnMissingKeepAlives() { RSocket rSocket = resumableRequesterState.rSocket(); - List errors = resumableRequesterState.errors().errors(); TestDuplexConnection connection = resumableRequesterState.connection(); Mono.delay(Duration.ofMillis(500)).block(); Assertions.assertThat(rSocket.isDisposed()).isFalse(); - Assertions.assertThat(errors).hasSize(0); Assertions.assertThat(connection.isDisposed()).isTrue(); } @@ -248,17 +238,12 @@ private boolean keepAliveFrameWithoutRespondFlag(ByteBuf frame) { static class RSocketState { private final RSocket rSocket; - private final Errors errors; private final TestDuplexConnection connection; private final LeaksTrackingByteBufAllocator allocator; public RSocketState( - RSocket rSocket, - Errors errors, - LeaksTrackingByteBufAllocator allocator, - TestDuplexConnection connection) { + RSocket rSocket, LeaksTrackingByteBufAllocator allocator, TestDuplexConnection connection) { this.rSocket = rSocket; - this.errors = errors; this.connection = connection; this.allocator = allocator; } @@ -271,10 +256,6 @@ public RSocket rSocket() { return rSocket; } - public Errors errors() { - return errors; - } - public LeaksTrackingByteBufAllocator alloc() { return allocator; } @@ -282,19 +263,16 @@ public LeaksTrackingByteBufAllocator alloc() { static class ResumableRSocketState { private final RSocket rSocket; - private final Errors errors; private final TestDuplexConnection connection; private final ResumableDuplexConnection resumableDuplexConnection; private final LeaksTrackingByteBufAllocator allocator; public ResumableRSocketState( RSocket rSocket, - Errors errors, TestDuplexConnection connection, ResumableDuplexConnection resumableDuplexConnection, LeaksTrackingByteBufAllocator allocator) { this.rSocket = rSocket; - this.errors = errors; this.connection = connection; this.resumableDuplexConnection = resumableDuplexConnection; this.allocator = allocator; @@ -312,25 +290,8 @@ public RSocket rSocket() { return rSocket; } - public Errors errors() { - return errors; - } - public LeaksTrackingByteBufAllocator alloc() { return allocator; } } - - static class Errors implements Consumer { - private final List errors = new ArrayList<>(); - - @Override - public void accept(Throwable throwable) { - errors.add(throwable); - } - - public List errors() { - return new ArrayList<>(errors); - } - } } diff --git a/rsocket-core/src/test/java/io/rsocket/core/RSocketLeaseTest.java b/rsocket-core/src/test/java/io/rsocket/core/RSocketLeaseTest.java index ddfbe4234..ab336b8cd 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/RSocketLeaseTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/RSocketLeaseTest.java @@ -85,7 +85,7 @@ void setUp() { requesterLeaseHandler = new RequesterLeaseHandler.Impl(TAG, leases -> leaseReceiver = leases); responderLeaseHandler = new ResponderLeaseHandler.Impl<>( - TAG, byteBufAllocator, stats -> leaseSender, err -> {}, Optional.empty()); + TAG, byteBufAllocator, stats -> leaseSender, Optional.empty()); ClientServerInputMultiplexer multiplexer = new ClientServerInputMultiplexer(connection, new InitializingInterceptorRegistry(), true); @@ -93,7 +93,6 @@ void setUp() { new RSocketRequester( multiplexer.asClientConnection(), payloadDecoder, - err -> {}, StreamIdSupplier.clientSupplier(), 0, 0, @@ -114,7 +113,6 @@ void setUp() { multiplexer.asServerConnection(), mockRSocketHandler, payloadDecoder, - err -> {}, responderLeaseHandler, 0); } diff --git a/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterSubscribersTest.java b/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterSubscribersTest.java index 00f74152a..4cd3a3a26 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterSubscribersTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterSubscribersTest.java @@ -66,7 +66,6 @@ void setUp() { new RSocketRequester( connection, PayloadDecoder.DEFAULT, - err -> {}, StreamIdSupplier.clientSupplier(), 0, 0, diff --git a/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterTest.java b/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterTest.java index e4943e9b0..1ba75f75a 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/RSocketRequesterTest.java @@ -24,10 +24,8 @@ import static io.rsocket.frame.FrameType.REQUEST_RESPONSE; import static io.rsocket.frame.FrameType.REQUEST_STREAM; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; @@ -122,13 +120,9 @@ public void tearDown() { @Test @Timeout(2_000) - public void testInvalidFrameOnStream0() { + public void testInvalidFrameOnStream0ShouldNotTerminateRSocket() { rule.connection.addToReceivedBuffer(RequestNFrameCodec.encode(rule.alloc(), 0, 10)); - assertThat("Unexpected errors.", rule.errors, hasSize(1)); - assertThat( - "Unexpected error received.", - rule.errors, - contains(instanceOf(IllegalStateException.class))); + Assertions.assertThat(rule.socket.isDisposed()).isFalse(); rule.assertHasNoLeaks(); } @@ -167,11 +161,8 @@ protected void hookOnSubscribe(Subscription subscription) { public void testHandleSetupException() { rule.connection.addToReceivedBuffer( ErrorFrameCodec.encode(rule.alloc(), 0, new RejectedSetupException("boom"))); - assertThat("Unexpected errors.", rule.errors, hasSize(1)); - assertThat( - "Unexpected error received.", - rule.errors, - contains(instanceOf(RejectedSetupException.class))); + Assertions.assertThatThrownBy(() -> rule.socket.onClose().block()) + .isInstanceOf(RejectedSetupException.class); rule.assertHasNoLeaks(); } @@ -242,7 +233,12 @@ public void testRequestReplyErrorOnSend() { Subscriber responseSub = TestSubscriber.create(10); response.subscribe(responseSub); - this.rule.assertNoConnectionErrors(); + this.rule + .socket + .onClose() + .as(StepVerifier::create) + .expectComplete() + .verify(Duration.ofMillis(100)); verify(responseSub).onSubscribe(any(Subscription.class)); @@ -1006,7 +1002,6 @@ protected RSocketRequester newRSocket() { return new RSocketRequester( connection, PayloadDecoder.ZERO_COPY, - throwable -> errors.add(throwable), StreamIdSupplier.clientSupplier(), 0, 0, diff --git a/rsocket-core/src/test/java/io/rsocket/core/RSocketResponderTest.java b/rsocket-core/src/test/java/io/rsocket/core/RSocketResponderTest.java index e34973848..036dc2eef 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/RSocketResponderTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/RSocketResponderTest.java @@ -59,7 +59,6 @@ import io.rsocket.util.DefaultPayload; import io.rsocket.util.EmptyPayload; import java.util.Collection; -import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Stream; @@ -138,7 +137,6 @@ public void testHandleResponseFrameNoError() throws Exception { Collection> sendSubscribers = rule.connection.getSendSubscribers(); assertThat("Request not sent.", sendSubscribers, hasSize(1)); - assertThat("Unexpected error.", rule.errors, is(empty())); Subscriber sendSub = sendSubscribers.iterator().next(); assertThat( "Unexpected frame sent.", @@ -152,7 +150,6 @@ public void testHandleResponseFrameNoError() throws Exception { public void testHandlerEmitsError() throws Exception { final int streamId = 4; rule.sendRequest(streamId, FrameType.REQUEST_STREAM); - assertThat("Unexpected error.", rule.errors, is(empty())); assertThat( "Unexpected frame sent.", frameType(rule.connection.awaitSend()), is(FrameType.ERROR)); } @@ -173,7 +170,6 @@ public Mono requestResponse(Payload payload) { }); rule.sendRequest(streamId, FrameType.REQUEST_RESPONSE); - assertThat("Unexpected error.", rule.errors, is(empty())); assertThat("Unexpected frame sent.", rule.connection.getSent(), is(empty())); rule.connection.addToReceivedBuffer(CancelFrameCodec.encode(allocator, streamId)); @@ -232,10 +228,6 @@ protected void hookOnSubscribe(Subscription subscription) { for (Runnable runnable : runnables) { rule.connection.clearSendReceiveBuffers(); runnable.run(); - Assertions.assertThat(rule.errors) - .first() - .isInstanceOf(IllegalArgumentException.class) - .hasToString("java.lang.IllegalArgumentException: " + INVALID_PAYLOAD_ERROR_MESSAGE); Assertions.assertThat(rule.connection.getSent()) .hasSize(1) .first() @@ -778,7 +770,6 @@ public void setAcceptingSocket(RSocket acceptingSocket) { this.acceptingSocket = acceptingSocket; connection = new TestDuplexConnection(alloc()); connectSub = TestSubscriber.create(); - errors = new ConcurrentLinkedQueue<>(); this.prefetch = Integer.MAX_VALUE; super.init(); } @@ -787,7 +778,6 @@ public void setAcceptingSocket(RSocket acceptingSocket, int prefetch) { this.acceptingSocket = acceptingSocket; connection = new TestDuplexConnection(alloc()); connectSub = TestSubscriber.create(); - errors = new ConcurrentLinkedQueue<>(); this.prefetch = prefetch; super.init(); } @@ -795,12 +785,7 @@ public void setAcceptingSocket(RSocket acceptingSocket, int prefetch) { @Override protected RSocketResponder newRSocket() { return new RSocketResponder( - connection, - acceptingSocket, - PayloadDecoder.ZERO_COPY, - throwable -> errors.add(throwable), - ResponderLeaseHandler.None, - 0); + connection, acceptingSocket, PayloadDecoder.ZERO_COPY, ResponderLeaseHandler.None, 0); } private void sendRequest(int streamId, FrameType frameType) { diff --git a/rsocket-core/src/test/java/io/rsocket/core/RSocketTest.java b/rsocket-core/src/test/java/io/rsocket/core/RSocketTest.java index 48ce150d6..f032942db 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/RSocketTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/RSocketTest.java @@ -16,11 +16,6 @@ package io.rsocket.core; -import static org.hamcrest.Matchers.empty; -import static org.hamcrest.Matchers.is; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.verify; - import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.rsocket.Payload; @@ -34,24 +29,18 @@ import io.rsocket.lease.RequesterLeaseHandler; import io.rsocket.lease.ResponderLeaseHandler; import io.rsocket.test.util.LocalDuplexConnection; -import io.rsocket.test.util.TestSubscriber; import io.rsocket.util.DefaultPayload; import io.rsocket.util.EmptyPayload; import java.time.Duration; -import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicReference; import org.assertj.core.api.Assertions; -import org.hamcrest.MatcherAssert; -import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExternalResource; import org.junit.runner.Description; import org.junit.runners.model.Statement; -import org.mockito.ArgumentCaptor; import org.reactivestreams.Publisher; -import org.reactivestreams.Subscriber; import reactor.core.publisher.DirectProcessor; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -62,16 +51,6 @@ public class RSocketTest { @Rule public final SocketRule rule = new SocketRule(); - public static void assertError(String s, String mode, ArrayList errors) { - for (Throwable t : errors) { - if (t.toString().equals(s)) { - return; - } - } - - Assert.fail("Expected " + mode + " connection error: " + s + " other errors " + errors.size()); - } - @Test(timeout = 2_000) public void testRequestReplyNoError() { StepVerifier.create(rule.crs.requestResponse(DefaultPayload.create("hello"))) @@ -89,14 +68,15 @@ public Mono requestResponse(Payload payload) { return Mono.error(new NullPointerException("Deliberate exception.")); } }); - Subscriber subscriber = TestSubscriber.create(); - rule.crs.requestResponse(EmptyPayload.INSTANCE).subscribe(subscriber); - verify(subscriber).onError(any(ApplicationErrorException.class)); - - // Client sees error through normal API - rule.assertNoClientErrors(); - - rule.assertServerError("java.lang.NullPointerException: Deliberate exception."); + rule.crs + .requestResponse(EmptyPayload.INSTANCE) + .as(StepVerifier::create) + .expectErrorSatisfies( + t -> + Assertions.assertThat(t) + .isInstanceOf(ApplicationErrorException.class) + .hasMessage("Deliberate exception.")) + .verify(Duration.ofMillis(100)); } @Test(timeout = 2000) @@ -109,21 +89,16 @@ public Mono requestResponse(Payload payload) { new CustomRSocketException(0x00000501, "Deliberate Custom exception.")); } }); - Subscriber subscriber = TestSubscriber.create(); - rule.crs.requestResponse(EmptyPayload.INSTANCE).subscribe(subscriber); - ArgumentCaptor customRSocketExceptionArgumentCaptor = - ArgumentCaptor.forClass(CustomRSocketException.class); - verify(subscriber).onError(customRSocketExceptionArgumentCaptor.capture()); - - Assert.assertEquals( - "Deliberate Custom exception.", - customRSocketExceptionArgumentCaptor.getValue().getMessage()); - Assert.assertEquals(0x00000501, customRSocketExceptionArgumentCaptor.getValue().errorCode()); - - // Client sees error through normal API - rule.assertNoClientErrors(); - - rule.assertServerError("CustomRSocketException (0x501): Deliberate Custom exception."); + rule.crs + .requestResponse(EmptyPayload.INSTANCE) + .as(StepVerifier::create) + .expectErrorSatisfies( + t -> + Assertions.assertThat(t) + .isInstanceOf(CustomRSocketException.class) + .hasMessage("Deliberate Custom exception.") + .hasFieldOrPropertyWithValue("errorCode", 0x00000501)) + .verify(); } @Test(timeout = 2000) @@ -147,9 +122,6 @@ public Flux requestChannel(Publisher payloads) { .expectNextCount(3) .expectComplete() .verify(Duration.ofMillis(5000)); - - rule.assertNoClientErrors(); - rule.assertNoServerErrors(); } @Test(timeout = 2000) @@ -413,8 +385,6 @@ public static class SocketRule extends ExternalResource { private RSocketResponder srs; private RSocket requestAcceptor; - private ArrayList clientErrors = new ArrayList<>(); - private ArrayList serverErrors = new ArrayList<>(); private LeaksTrackingByteBufAllocator allocator; @@ -479,7 +449,6 @@ public Flux requestChannel(Publisher payloads) { serverConnection, requestAcceptor, PayloadDecoder.DEFAULT, - throwable -> serverErrors.add(throwable), ResponderLeaseHandler.None, 0); @@ -487,7 +456,6 @@ public Flux requestChannel(Publisher payloads) { new RSocketRequester( clientConnection, PayloadDecoder.DEFAULT, - throwable -> clientErrors.add(throwable), StreamIdSupplier.clientSupplier(), 0, 0, @@ -501,28 +469,5 @@ public void setRequestAcceptor(RSocket requestAcceptor) { this.requestAcceptor = requestAcceptor; init(); } - - public void assertNoErrors() { - assertNoClientErrors(); - assertNoServerErrors(); - } - - public void assertNoClientErrors() { - MatcherAssert.assertThat( - "Unexpected error on the client connection.", clientErrors, is(empty())); - } - - public void assertNoServerErrors() { - MatcherAssert.assertThat( - "Unexpected error on the server connection.", serverErrors, is(empty())); - } - - public void assertClientError(String s) { - assertError(s, "client", this.clientErrors); - } - - public void assertServerError(String s) { - assertError(s, "server", this.serverErrors); - } } } diff --git a/rsocket-core/src/test/java/io/rsocket/core/SetupRejectionTest.java b/rsocket-core/src/test/java/io/rsocket/core/SetupRejectionTest.java index 75a5e070e..2957a051e 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/SetupRejectionTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/SetupRejectionTest.java @@ -18,8 +18,6 @@ import io.rsocket.transport.ServerTransport; import io.rsocket.util.DefaultPayload; import java.time.Duration; -import java.util.ArrayList; -import java.util.List; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import reactor.core.publisher.Mono; @@ -53,12 +51,10 @@ void requesterStreamsTerminatedOnZeroErrorFrame() { LeaksTrackingByteBufAllocator allocator = LeaksTrackingByteBufAllocator.instrument(ByteBufAllocator.DEFAULT); TestDuplexConnection conn = new TestDuplexConnection(allocator); - List errors = new ArrayList<>(); RSocketRequester rSocket = new RSocketRequester( conn, DefaultPayload::create, - errors::add, StreamIdSupplier.clientSupplier(), 0, 0, @@ -83,7 +79,6 @@ void requesterStreamsTerminatedOnZeroErrorFrame() { err -> err instanceof RejectedSetupException && errorMsg.equals(err.getMessage())) .verify(Duration.ofSeconds(5)); - assertThat(errors).hasSize(1); assertThat(rSocket.isDisposed()).isTrue(); } @@ -96,7 +91,6 @@ void requesterNewStreamsTerminatedAfterZeroErrorFrame() { new RSocketRequester( conn, DefaultPayload::create, - err -> {}, StreamIdSupplier.clientSupplier(), 0, 0, From d880f51862b71e8790a9883a05963991f779e4a8 Mon Sep 17 00:00:00 2001 From: Oleh Dokuka Date: Mon, 11 May 2020 16:30:39 +0300 Subject: [PATCH 21/25] fixes onClose behaviour to not error on shutdown (#833) --- .../io/rsocket/core/RSocketRequester.java | 26 ++++++++------- .../io/rsocket/core/RSocketResponder.java | 7 ++-- .../java/io/rsocket/core/RSocketTest.java | 33 +++++++++++++++++++ 3 files changed, 50 insertions(+), 16 deletions(-) diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java index cdfda0755..f7fb161fd 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketRequester.java @@ -50,7 +50,6 @@ import io.rsocket.keepalive.KeepAliveSupport; import io.rsocket.lease.RequesterLeaseHandler; import java.nio.channels.ClosedChannelException; -import java.util.concurrent.CancellationException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import java.util.function.Consumer; @@ -137,10 +136,7 @@ class RSocketRequester implements RSocket { // DO NOT Change the order here. The Send processor must be subscribed to before receiving this.sendProcessor = new UnboundedProcessor<>(); - connection - .onClose() - .or(onClose) - .subscribe(null, this::tryTerminateOnConnectionError, this::tryTerminateOnConnectionClose); + connection.onClose().subscribe(null, this::tryTerminateOnConnectionError, this::tryShutdown); connection.send(sendProcessor).subscribe(null, this::handleSendProcessorError); connection.receive().subscribe(this::handleIncomingFrames, e -> {}); @@ -188,7 +184,7 @@ public double availability() { @Override public void dispose() { - tryTerminate(() -> new CancellationException("Disposed")); + tryShutdown(); } @Override @@ -708,10 +704,6 @@ private void tryTerminateOnConnectionError(Throwable e) { tryTerminate(() -> e); } - private void tryTerminateOnConnectionClose() { - tryTerminate(() -> CLOSED_CHANNEL_EXCEPTION); - } - private void tryTerminateOnZeroError(ByteBuf errorFrame) { tryTerminate(() -> Exceptions.from(0, errorFrame)); } @@ -725,6 +717,14 @@ private void tryTerminate(Supplier errorSupplier) { } } + private void tryShutdown() { + if (terminationError == null) { + if (TERMINATION_ERROR.compareAndSet(this, null, CLOSED_CHANNEL_EXCEPTION)) { + terminate(CLOSED_CHANNEL_EXCEPTION); + } + } + } + private void terminate(Throwable e) { connection.dispose(); leaseHandler.dispose(); @@ -760,7 +760,11 @@ private void terminate(Throwable e) { senders.clear(); receivers.clear(); sendProcessor.dispose(); - onClose.onError(e); + if (e == CLOSED_CHANNEL_EXCEPTION) { + onClose.onComplete(); + } else { + onClose.onError(e); + } } private void handleSendProcessorError(Throwable t) { diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java index ca5e605c7..d3860e5f2 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketResponder.java @@ -75,7 +75,6 @@ class RSocketResponder implements RSocket { private final PayloadDecoder payloadDecoder; private final ResponderLeaseHandler leaseHandler; private final Disposable leaseHandlerDisposable; - private final MonoProcessor onClose; private volatile Throwable terminationError; private static final AtomicReferenceFieldUpdater TERMINATION_ERROR = @@ -110,7 +109,6 @@ class RSocketResponder implements RSocket { this.leaseHandler = leaseHandler; this.sendingSubscriptions = new SynchronizedIntObjectHashMap<>(); this.channelProcessors = new SynchronizedIntObjectHashMap<>(); - this.onClose = MonoProcessor.create(); // DO NOT Change the order here. The Send processor must be subscribed to before receiving // connections @@ -123,7 +121,6 @@ class RSocketResponder implements RSocket { this.connection .onClose() - .or(onClose) .subscribe(null, this::tryTerminateOnConnectionError, this::tryTerminateOnConnectionClose); } @@ -256,12 +253,12 @@ public void dispose() { @Override public boolean isDisposed() { - return onClose.isDisposed(); + return connection.isDisposed(); } @Override public Mono onClose() { - return onClose; + return connection.onClose(); } private void cleanup(Throwable e) { diff --git a/rsocket-core/src/test/java/io/rsocket/core/RSocketTest.java b/rsocket-core/src/test/java/io/rsocket/core/RSocketTest.java index f032942db..692894fd6 100644 --- a/rsocket-core/src/test/java/io/rsocket/core/RSocketTest.java +++ b/rsocket-core/src/test/java/io/rsocket/core/RSocketTest.java @@ -41,6 +41,8 @@ import org.junit.runner.Description; import org.junit.runners.model.Statement; import org.reactivestreams.Publisher; +import reactor.core.Disposable; +import reactor.core.Disposables; import reactor.core.publisher.DirectProcessor; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -51,6 +53,34 @@ public class RSocketTest { @Rule public final SocketRule rule = new SocketRule(); + @Test + public void rsocketDisposalShouldEndupWithNoErrorsOnClose() { + RSocket requestHandlingRSocket = + new RSocket() { + final Disposable disposable = Disposables.single(); + + @Override + public void dispose() { + disposable.dispose(); + } + + @Override + public boolean isDisposed() { + return disposable.isDisposed(); + } + }; + rule.setRequestAcceptor(requestHandlingRSocket); + rule.crs + .onClose() + .as(StepVerifier::create) + .expectSubscription() + .then(rule.crs::dispose) + .expectComplete() + .verify(Duration.ofMillis(100)); + + Assertions.assertThat(requestHandlingRSocket.isDisposed()).isTrue(); + } + @Test(timeout = 2_000) public void testRequestReplyNoError() { StepVerifier.create(rule.crs.requestResponse(DefaultPayload.create("hello"))) @@ -413,6 +443,9 @@ protected void init() { LocalDuplexConnection clientConnection = new LocalDuplexConnection("client", allocator, serverProcessor, clientProcessor); + clientConnection.onClose().doFinally(__ -> serverConnection.dispose()).subscribe(); + serverConnection.onClose().doFinally(__ -> clientConnection.dispose()).subscribe(); + requestAcceptor = null != requestAcceptor ? requestAcceptor From a0e741c5af29a1ca16c8acaf316d6ae2067be776 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Mon, 11 May 2020 18:18:57 +0100 Subject: [PATCH 22/25] includes LimitRateInterceptor as a built-in interceptor (#834) --- .../io/rsocket/core/RSocketConnector.java | 1 + .../java/io/rsocket/core/RSocketServer.java | 1 + .../rsocket/plugins/LimitRateInterceptor.java | 133 ++++++++++++++++++ .../plugins/LimitRateInterceptorExample.java | 116 +++------------ 4 files changed, 151 insertions(+), 100 deletions(-) create mode 100644 rsocket-core/src/main/java/io/rsocket/plugins/LimitRateInterceptor.java diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java index d9622e0f0..02f1a51cc 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketConnector.java @@ -221,6 +221,7 @@ public RSocketConnector keepAlive(Duration interval, Duration maxLifeTime) { * * @param configurer a configurer to customize interception with. * @return the same instance for method chaining + * @see io.rsocket.plugins.LimitRateInterceptor */ public RSocketConnector interceptors(Consumer configurer) { configurer.accept(this.interceptors); diff --git a/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java b/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java index 6390d44dd..c5734cecc 100644 --- a/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java +++ b/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java @@ -142,6 +142,7 @@ public RSocketServer acceptor(SocketAcceptor acceptor) { * * @param configurer a configurer to customize interception with. * @return the same instance for method chaining + * @see io.rsocket.plugins.LimitRateInterceptor */ public RSocketServer interceptors(Consumer configurer) { configurer.accept(this.interceptors); diff --git a/rsocket-core/src/main/java/io/rsocket/plugins/LimitRateInterceptor.java b/rsocket-core/src/main/java/io/rsocket/plugins/LimitRateInterceptor.java new file mode 100644 index 000000000..d7d9742d0 --- /dev/null +++ b/rsocket-core/src/main/java/io/rsocket/plugins/LimitRateInterceptor.java @@ -0,0 +1,133 @@ +/* + * Copyright 2015-2020 the original author or authors. + * + * Licensed 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 io.rsocket.plugins; + +import io.rsocket.Payload; +import io.rsocket.RSocket; +import io.rsocket.util.RSocketProxy; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Flux; + +/** + * Interceptor that adds {@link Flux#limitRate(int, int)} to publishers of outbound streams that + * breaks down or aggregates demand values from the remote end (i.e. {@code REQUEST_N} frames) into + * batches of a uniform size. For example the remote may request {@code Long.MAXVALUE} or it may + * start requesting one at a time, in both cases with the limit set to 64, the publisher will see a + * demand of 64 to start and subsequent batches of 48, i.e. continuing to prefetch and refill an + * internal queue when it falls to 75% full. The high and low tide marks are configurable. + * + *

See static factory methods to create an instance for a requester or for a responder. + * + *

Note: keep in mind that the {@code limitRate} operator always uses requests + * the same request values, even if the remote requests less than the limit. For example given a + * limit of 64, if the remote requests 4, 64 will be prefetched of which 4 will be sent and 60 will + * be cached. + * + * @since 1.0 + */ +public class LimitRateInterceptor implements RSocketInterceptor { + + private final int highTide; + private final int lowTide; + private final boolean requesterProxy; + + private LimitRateInterceptor(int highTide, int lowTide, boolean requesterProxy) { + this.highTide = highTide; + this.lowTide = lowTide; + this.requesterProxy = requesterProxy; + } + + @Override + public RSocket apply(RSocket socket) { + return requesterProxy ? new RequesterProxy(socket) : new ResponderProxy(socket); + } + + /** + * Create an interceptor for an {@code RSocket} that handles request-stream and/or request-channel + * interactions. + * + * @param prefetchRate the prefetch rate to pass to {@link Flux#limitRate(int)} + * @return the created interceptor + */ + public static LimitRateInterceptor forResponder(int prefetchRate) { + return forResponder(prefetchRate, prefetchRate); + } + + /** + * Create an interceptor for an {@code RSocket} that handles request-stream and/or request-channel + * interactions with more control over the overall prefetch rate and replenish threshold. + * + * @param highTide the high tide value to pass to {@link Flux#limitRate(int, int)} + * @param lowTide the low tide value to pass to {@link Flux#limitRate(int, int)} + * @return the created interceptor + */ + public static LimitRateInterceptor forResponder(int highTide, int lowTide) { + return new LimitRateInterceptor(highTide, lowTide, false); + } + + /** + * Create an interceptor for an {@code RSocket} that performs request-channel interactions. + * + * @param prefetchRate the prefetch rate to pass to {@link Flux#limitRate(int)} + * @return the created interceptor + */ + public static LimitRateInterceptor forRequester(int prefetchRate) { + return forRequester(prefetchRate, prefetchRate); + } + + /** + * Create an interceptor for an {@code RSocket} that performs request-channel interactions with + * more control over the overall prefetch rate and replenish threshold. + * + * @param highTide the high tide value to pass to {@link Flux#limitRate(int, int)} + * @param lowTide the low tide value to pass to {@link Flux#limitRate(int, int)} + * @return the created interceptor + */ + public static LimitRateInterceptor forRequester(int highTide, int lowTide) { + return new LimitRateInterceptor(highTide, lowTide, true); + } + + /** Responder side proxy, limits response streams. */ + private class ResponderProxy extends RSocketProxy { + + ResponderProxy(RSocket source) { + super(source); + } + + @Override + public Flux requestStream(Payload payload) { + return super.requestStream(payload).limitRate(highTide, lowTide); + } + + @Override + public Flux requestChannel(Publisher payloads) { + return super.requestChannel(payloads).limitRate(highTide, lowTide); + } + } + + /** Requester side proxy, limits channel request stream. */ + private class RequesterProxy extends RSocketProxy { + + RequesterProxy(RSocket source) { + super(source); + } + + @Override + public Flux requestChannel(Publisher payloads) { + return super.requestChannel(Flux.from(payloads).limitRate(highTide, lowTide)); + } + } +} diff --git a/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/plugins/LimitRateInterceptorExample.java b/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/plugins/LimitRateInterceptorExample.java index ac473d7b1..67a85b67f 100644 --- a/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/plugins/LimitRateInterceptorExample.java +++ b/rsocket-examples/src/main/java/io/rsocket/examples/transport/tcp/plugins/LimitRateInterceptorExample.java @@ -5,73 +5,64 @@ import io.rsocket.SocketAcceptor; import io.rsocket.core.RSocketConnector; import io.rsocket.core.RSocketServer; -import io.rsocket.examples.transport.tcp.stream.StreamingClient; -import io.rsocket.plugins.RSocketInterceptor; +import io.rsocket.plugins.LimitRateInterceptor; import io.rsocket.transport.netty.client.TcpClientTransport; import io.rsocket.transport.netty.server.TcpServerTransport; import io.rsocket.util.DefaultPayload; -import io.rsocket.util.RSocketProxy; import java.time.Duration; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; import org.reactivestreams.Publisher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import reactor.core.publisher.Flux; -import reactor.util.concurrent.Queues; public class LimitRateInterceptorExample { - private static final Logger logger = LoggerFactory.getLogger(StreamingClient.class); + private static final Logger logger = LoggerFactory.getLogger(LimitRateInterceptorExample.class); public static void main(String[] args) { - BlockingQueue requests = new ArrayBlockingQueue<>(100); RSocketServer.create( SocketAcceptor.with( new RSocket() { @Override public Flux requestStream(Payload payload) { return Flux.interval(Duration.ofMillis(100)) - .doOnRequest(e -> requests.add("Responder requestN(" + e + ")")) + .doOnRequest( + e -> logger.debug("Server publisher receives request for " + e)) .map(aLong -> DefaultPayload.create("Interval: " + aLong)); } @Override public Flux requestChannel(Publisher payloads) { return Flux.from(payloads) - .doOnRequest(e -> requests.add("Responder requestN(" + e + ")")); + .doOnRequest( + e -> logger.debug("Server publisher receives request for " + e)); } })) - .interceptors( - ir -> - ir.forRequester(LimitRateInterceptor.forRequester()) - .forResponder(LimitRateInterceptor.forResponder())) + .interceptors(registry -> registry.forResponder(LimitRateInterceptor.forResponder(64))) .bind(TcpServerTransport.create("localhost", 7000)) .subscribe(); RSocket socket = RSocketConnector.create() - .interceptors( - ir -> - ir.forRequester(LimitRateInterceptor.forRequester()) - .forResponder(LimitRateInterceptor.forResponder())) + .interceptors(registry -> registry.forRequester(LimitRateInterceptor.forRequester(64))) .connect(TcpClientTransport.create("localhost", 7000)) .block(); + logger.debug( + "\n\nStart of requestStream interaction\n" + "----------------------------------\n"); + socket .requestStream(DefaultPayload.create("Hello")) - .doOnRequest(e -> requests.add("Requester requestN(" + e + ")")) + .doOnRequest(e -> logger.debug("Client sends requestN(" + e + ")")) .map(Payload::getDataUtf8) .doOnNext(logger::debug) .take(10) .then() .block(); - requests.forEach(request -> logger.debug("Requested : {}", request)); - requests.clear(); + logger.debug( + "\n\nStart of requestChannel interaction\n" + "-----------------------------------\n"); - logger.debug("-----------------------------------------------------------------"); - logger.debug("Does requestChannel"); socket .requestChannel( Flux.generate( @@ -80,8 +71,8 @@ public Flux requestChannel(Publisher payloads) { sink.next(DefaultPayload.create("Next " + s)); return ++s; }) - .doOnRequest(e -> requests.add("Requester Upstream requestN(" + e + ")"))) - .doOnRequest(e -> requests.add("Requester Downstream requestN(" + e + ")")) + .doOnRequest(e -> logger.debug("Client publisher receives request for " + e))) + .doOnRequest(e -> logger.debug("Client sends requestN(" + e + ")")) .map(Payload::getDataUtf8) .doOnNext(logger::debug) .take(10) @@ -89,80 +80,5 @@ public Flux requestChannel(Publisher payloads) { .doFinally(signalType -> socket.dispose()) .then() .block(); - - requests.forEach(request -> logger.debug("Requested : {}", request)); - } - - static class LimitRateInterceptor implements RSocketInterceptor { - - final boolean requesterSide; - final int highTide; - final int lowTide; - - LimitRateInterceptor(boolean requesterSide, int highTide, int lowTide) { - this.requesterSide = requesterSide; - this.highTide = highTide; - this.lowTide = lowTide; - } - - @Override - public RSocket apply(RSocket socket) { - return new LimitRateRSocket(socket, requesterSide, highTide, lowTide); - } - - public static LimitRateInterceptor forRequester() { - return forRequester(Queues.SMALL_BUFFER_SIZE); - } - - public static LimitRateInterceptor forRequester(int limit) { - return forRequester(limit, limit); - } - - public static LimitRateInterceptor forRequester(int highTide, int lowTide) { - return new LimitRateInterceptor(true, highTide, lowTide); - } - - public static LimitRateInterceptor forResponder() { - return forRequester(Queues.SMALL_BUFFER_SIZE); - } - - public static LimitRateInterceptor forResponder(int limit) { - return forRequester(limit, limit); - } - - public static LimitRateInterceptor forResponder(int highTide, int lowTide) { - return new LimitRateInterceptor(false, highTide, lowTide); - } - } - - static class LimitRateRSocket extends RSocketProxy { - - final boolean requesterSide; - final int highTide; - final int lowTide; - - public LimitRateRSocket(RSocket source, boolean requesterSide, int highTide, int lowTide) { - super(source); - this.requesterSide = requesterSide; - this.highTide = highTide; - this.lowTide = lowTide; - } - - @Override - public Flux requestStream(Payload payload) { - Flux flux = super.requestStream(payload); - if (requesterSide) { - return flux; - } - return flux.limitRate(highTide, lowTide); - } - - @Override - public Flux requestChannel(Publisher payloads) { - if (requesterSide) { - return super.requestChannel(Flux.from(payloads).limitRate(highTide, lowTide)); - } - return super.requestChannel(payloads).limitRate(highTide, lowTide); - } } } From 08c2a78f25c0b5e78103e95cbf90144cd7ea118a Mon Sep 17 00:00:00 2001 From: Oleh Dokuka Date: Tue, 12 May 2020 02:02:43 +0300 Subject: [PATCH 23/25] provides support for TracingMetadata (#824) * provides support for TracingMetadata Signed-off-by: Oleh Dokuka * improves docs Signed-off-by: Oleh Dokuka --- .../io/rsocket/metadata/TracingMetadata.java | 110 +++++++++ .../metadata/TracingMetadataCodec.java | 172 ++++++++++++++ .../metadata/TracingMetadataCodecTest.java | 209 ++++++++++++++++++ 3 files changed, 491 insertions(+) create mode 100644 rsocket-core/src/main/java/io/rsocket/metadata/TracingMetadata.java create mode 100644 rsocket-core/src/main/java/io/rsocket/metadata/TracingMetadataCodec.java create mode 100644 rsocket-core/src/test/java/io/rsocket/metadata/TracingMetadataCodecTest.java diff --git a/rsocket-core/src/main/java/io/rsocket/metadata/TracingMetadata.java b/rsocket-core/src/main/java/io/rsocket/metadata/TracingMetadata.java new file mode 100644 index 000000000..d276a9436 --- /dev/null +++ b/rsocket-core/src/main/java/io/rsocket/metadata/TracingMetadata.java @@ -0,0 +1,110 @@ +/* + * Copyright 2015-2020 the original author or authors. + * + * Licensed 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 io.rsocket.metadata; + +/** + * Represents decoded tracing metadata which is fully compatible with Zipkin B3 propagation + * + * @since 1.0 + */ +public final class TracingMetadata { + + final long traceIdHigh; + final long traceId; + private final boolean hasParentId; + final long parentId; + final long spanId; + final boolean isEmpty; + final boolean isNotSampled; + final boolean isSampled; + final boolean isDebug; + + TracingMetadata( + long traceIdHigh, + long traceId, + long spanId, + boolean hasParentId, + long parentId, + boolean isEmpty, + boolean isNotSampled, + boolean isSampled, + boolean isDebug) { + this.traceIdHigh = traceIdHigh; + this.traceId = traceId; + this.spanId = spanId; + this.hasParentId = hasParentId; + this.parentId = parentId; + this.isEmpty = isEmpty; + this.isNotSampled = isNotSampled; + this.isSampled = isSampled; + this.isDebug = isDebug; + } + + /** When non-zero, the trace containing this span uses 128-bit trace identifiers. */ + public long traceIdHigh() { + return traceIdHigh; + } + + /** Unique 8-byte identifier for a trace, set on all spans within it. */ + public long traceId() { + return traceId; + } + + /** Indicates if the parent's {@link #spanId} or if this the root span in a trace. */ + public final boolean hasParent() { + return hasParentId; + } + + /** Returns the parent's {@link #spanId} where zero implies absent. */ + public long parentId() { + return parentId; + } + + /** + * Unique 8-byte identifier of this span within a trace. + * + *

A span is uniquely identified in storage by ({@linkplain #traceId}, {@linkplain #spanId}). + */ + public long spanId() { + return spanId; + } + + /** Indicates that trace IDs should be accepted for tracing. */ + public boolean isSampled() { + return isSampled; + } + + /** Indicates that trace IDs should be force traced. */ + public boolean isDebug() { + return isDebug; + } + + /** Includes that there is sampling information and no trace IDs. */ + public boolean isEmpty() { + return isEmpty; + } + + /** + * Indicated that sampling decision is present. If {@code false} means that decision is unknown + * and says explicitly that {@link #isDebug()} and {@link #isSampled()} also returns {@code + * false}. + */ + public boolean isDecided() { + return isNotSampled || isDebug || isSampled; + } +} diff --git a/rsocket-core/src/main/java/io/rsocket/metadata/TracingMetadataCodec.java b/rsocket-core/src/main/java/io/rsocket/metadata/TracingMetadataCodec.java new file mode 100644 index 000000000..eb44956f6 --- /dev/null +++ b/rsocket-core/src/main/java/io/rsocket/metadata/TracingMetadataCodec.java @@ -0,0 +1,172 @@ +package io.rsocket.metadata; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; + +/** + * Represents codes for tracing metadata which is fully compatible with Zipkin B3 propagation + * + * @since 1.0 + */ +public class TracingMetadataCodec { + + static final int FLAG_EXTENDED_TRACE_ID_SIZE = 0b0000_1000; + static final int FLAG_INCLUDE_PARENT_ID = 0b0000_0100; + static final int FLAG_NOT_SAMPLED = 0b0001_0000; + static final int FLAG_SAMPLED = 0b0010_0000; + static final int FLAG_DEBUG = 0b0100_0000; + static final int FLAG_IDS_SET = 0b1000_0000; + + public static ByteBuf encodeEmpty(ByteBufAllocator allocator, Flags flag) { + + return encode(allocator, true, 0, 0, false, 0, 0, false, flag); + } + + public static ByteBuf encode128( + ByteBufAllocator allocator, + long traceIdHigh, + long traceId, + long spanId, + long parentId, + Flags flag) { + + return encode(allocator, false, traceIdHigh, traceId, true, spanId, parentId, true, flag); + } + + public static ByteBuf encode128( + ByteBufAllocator allocator, long traceIdHigh, long traceId, long spanId, Flags flag) { + + return encode(allocator, false, traceIdHigh, traceId, true, spanId, 0, false, flag); + } + + public static ByteBuf encode64( + ByteBufAllocator allocator, long traceId, long spanId, long parentId, Flags flag) { + + return encode(allocator, false, 0, traceId, false, spanId, parentId, true, flag); + } + + public static ByteBuf encode64( + ByteBufAllocator allocator, long traceId, long spanId, Flags flag) { + return encode(allocator, false, 0, traceId, false, spanId, 0, false, flag); + } + + static ByteBuf encode( + ByteBufAllocator allocator, + boolean isEmpty, + long traceIdHigh, + long traceId, + boolean extendedTraceId, + long spanId, + long parentId, + boolean includesParent, + Flags flag) { + int size = + 1 + + (isEmpty + ? 0 + : (Long.BYTES + + Long.BYTES + + (extendedTraceId ? Long.BYTES : 0) + + (includesParent ? Long.BYTES : 0))); + final ByteBuf buffer = allocator.buffer(size); + + int byteFlags = 0; + switch (flag) { + case NOT_SAMPLE: + byteFlags |= FLAG_NOT_SAMPLED; + break; + case SAMPLE: + byteFlags |= FLAG_SAMPLED; + break; + case DEBUG: + byteFlags |= FLAG_DEBUG; + break; + } + + if (isEmpty) { + return buffer.writeByte(byteFlags); + } + + byteFlags |= FLAG_IDS_SET; + + if (extendedTraceId) { + byteFlags |= FLAG_EXTENDED_TRACE_ID_SIZE; + } + + if (includesParent) { + byteFlags |= FLAG_INCLUDE_PARENT_ID; + } + + buffer.writeByte(byteFlags); + + if (extendedTraceId) { + buffer.writeLong(traceIdHigh); + } + + buffer.writeLong(traceId).writeLong(spanId); + + if (includesParent) { + buffer.writeLong(parentId); + } + + return buffer; + } + + public static TracingMetadata decode(ByteBuf byteBuf) { + byteBuf.markReaderIndex(); + try { + byte flags = byteBuf.readByte(); + boolean isNotSampled = (flags & FLAG_NOT_SAMPLED) == FLAG_NOT_SAMPLED; + boolean isSampled = (flags & FLAG_SAMPLED) == FLAG_SAMPLED; + boolean isDebug = (flags & FLAG_DEBUG) == FLAG_DEBUG; + boolean isIDSet = (flags & FLAG_IDS_SET) == FLAG_IDS_SET; + + if (!isIDSet) { + return new TracingMetadata(0, 0, 0, false, 0, true, isNotSampled, isSampled, isDebug); + } + + boolean extendedTraceId = + (flags & FLAG_EXTENDED_TRACE_ID_SIZE) == FLAG_EXTENDED_TRACE_ID_SIZE; + + long traceIdHigh; + if (extendedTraceId) { + traceIdHigh = byteBuf.readLong(); + } else { + traceIdHigh = 0; + } + + long traceId = byteBuf.readLong(); + long spanId = byteBuf.readLong(); + + boolean includesParent = (flags & FLAG_INCLUDE_PARENT_ID) == FLAG_INCLUDE_PARENT_ID; + + long parentId; + if (includesParent) { + parentId = byteBuf.readLong(); + } else { + parentId = 0; + } + + return new TracingMetadata( + traceIdHigh, + traceId, + spanId, + includesParent, + parentId, + false, + isNotSampled, + isSampled, + isDebug); + } finally { + byteBuf.resetReaderIndex(); + } + } + + public enum Flags { + UNDECIDED, + NOT_SAMPLE, + SAMPLE, + DEBUG + } +} diff --git a/rsocket-core/src/test/java/io/rsocket/metadata/TracingMetadataCodecTest.java b/rsocket-core/src/test/java/io/rsocket/metadata/TracingMetadataCodecTest.java new file mode 100644 index 000000000..cb8478c13 --- /dev/null +++ b/rsocket-core/src/test/java/io/rsocket/metadata/TracingMetadataCodecTest.java @@ -0,0 +1,209 @@ +package io.rsocket.metadata; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.util.ReferenceCounted; +import io.rsocket.buffer.LeaksTrackingByteBufAllocator; +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.Stream; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +public class TracingMetadataCodecTest { + + private static Stream flags() { + return Stream.of(TracingMetadataCodec.Flags.values()); + } + + @ParameterizedTest + @MethodSource("flags") + public void shouldEncodeEmptyTrace(TracingMetadataCodec.Flags expectedFlag) { + LeaksTrackingByteBufAllocator allocator = + LeaksTrackingByteBufAllocator.instrument(ByteBufAllocator.DEFAULT); + ByteBuf byteBuf = TracingMetadataCodec.encodeEmpty(allocator, expectedFlag); + + TracingMetadata tracingMetadata = TracingMetadataCodec.decode(byteBuf); + + Assertions.assertThat(tracingMetadata) + .matches(TracingMetadata::isEmpty) + .matches( + tm -> { + switch (expectedFlag) { + case UNDECIDED: + return !tm.isDecided(); + case NOT_SAMPLE: + return tm.isDecided() && !tm.isSampled(); + case SAMPLE: + return tm.isDecided() && tm.isSampled(); + case DEBUG: + return tm.isDecided() && tm.isDebug(); + } + return false; + }); + Assertions.assertThat(byteBuf).matches(ReferenceCounted::release); + allocator.assertHasNoLeaks(); + } + + @ParameterizedTest + @MethodSource("flags") + public void shouldEncodeTrace64WithParent(TracingMetadataCodec.Flags expectedFlag) { + long traceId = ThreadLocalRandom.current().nextLong(); + long spanId = ThreadLocalRandom.current().nextLong(); + long parentId = ThreadLocalRandom.current().nextLong(); + LeaksTrackingByteBufAllocator allocator = + LeaksTrackingByteBufAllocator.instrument(ByteBufAllocator.DEFAULT); + ByteBuf byteBuf = + TracingMetadataCodec.encode64(allocator, traceId, spanId, parentId, expectedFlag); + + TracingMetadata tracingMetadata = TracingMetadataCodec.decode(byteBuf); + + Assertions.assertThat(tracingMetadata) + .matches(metadata -> !metadata.isEmpty()) + .matches(tm -> tm.traceIdHigh() == 0) + .matches(tm -> tm.traceId() == traceId) + .matches(tm -> tm.spanId() == spanId) + .matches(tm -> tm.hasParent()) + .matches(tm -> tm.parentId() == parentId) + .matches( + tm -> { + switch (expectedFlag) { + case UNDECIDED: + return !tm.isDecided(); + case NOT_SAMPLE: + return tm.isDecided() && !tm.isSampled(); + case SAMPLE: + return tm.isDecided() && tm.isSampled(); + case DEBUG: + return tm.isDecided() && tm.isDebug(); + } + return false; + }); + Assertions.assertThat(byteBuf).matches(ReferenceCounted::release); + allocator.assertHasNoLeaks(); + } + + @ParameterizedTest + @MethodSource("flags") + public void shouldEncodeTrace64(TracingMetadataCodec.Flags expectedFlag) { + long traceId = ThreadLocalRandom.current().nextLong(); + long spanId = ThreadLocalRandom.current().nextLong(); + LeaksTrackingByteBufAllocator allocator = + LeaksTrackingByteBufAllocator.instrument(ByteBufAllocator.DEFAULT); + ByteBuf byteBuf = TracingMetadataCodec.encode64(allocator, traceId, spanId, expectedFlag); + + TracingMetadata tracingMetadata = TracingMetadataCodec.decode(byteBuf); + + Assertions.assertThat(tracingMetadata) + .matches(metadata -> !metadata.isEmpty()) + .matches(tm -> tm.traceIdHigh() == 0) + .matches(tm -> tm.traceId() == traceId) + .matches(tm -> tm.spanId() == spanId) + .matches(tm -> !tm.hasParent()) + .matches(tm -> tm.parentId() == 0) + .matches( + tm -> { + switch (expectedFlag) { + case UNDECIDED: + return !tm.isDecided(); + case NOT_SAMPLE: + return tm.isDecided() && !tm.isSampled(); + case SAMPLE: + return tm.isDecided() && tm.isSampled(); + case DEBUG: + return tm.isDecided() && tm.isDebug(); + } + return false; + }); + Assertions.assertThat(byteBuf).matches(ReferenceCounted::release); + allocator.assertHasNoLeaks(); + } + + @ParameterizedTest + @MethodSource("flags") + public void shouldEncodeTrace128WithParent(TracingMetadataCodec.Flags expectedFlag) { + long traceIdHighLocal; + do { + traceIdHighLocal = ThreadLocalRandom.current().nextLong(); + + } while (traceIdHighLocal == 0); + long traceIdHigh = traceIdHighLocal; + long traceId = ThreadLocalRandom.current().nextLong(); + long spanId = ThreadLocalRandom.current().nextLong(); + long parentId = ThreadLocalRandom.current().nextLong(); + LeaksTrackingByteBufAllocator allocator = + LeaksTrackingByteBufAllocator.instrument(ByteBufAllocator.DEFAULT); + ByteBuf byteBuf = + TracingMetadataCodec.encode128( + allocator, traceIdHigh, traceId, spanId, parentId, expectedFlag); + + TracingMetadata tracingMetadata = TracingMetadataCodec.decode(byteBuf); + + Assertions.assertThat(tracingMetadata) + .matches(metadata -> !metadata.isEmpty()) + .matches(tm -> tm.traceIdHigh() == traceIdHigh) + .matches(tm -> tm.traceId() == traceId) + .matches(tm -> tm.spanId() == spanId) + .matches(tm -> tm.hasParent()) + .matches(tm -> tm.parentId() == parentId) + .matches( + tm -> { + switch (expectedFlag) { + case UNDECIDED: + return !tm.isDecided(); + case NOT_SAMPLE: + return tm.isDecided() && !tm.isSampled(); + case SAMPLE: + return tm.isDecided() && tm.isSampled(); + case DEBUG: + return tm.isDecided() && tm.isDebug(); + } + return false; + }); + Assertions.assertThat(byteBuf).matches(ReferenceCounted::release); + allocator.assertHasNoLeaks(); + } + + @ParameterizedTest + @MethodSource("flags") + public void shouldEncodeTrace128(TracingMetadataCodec.Flags expectedFlag) { + long traceIdHighLocal; + do { + traceIdHighLocal = ThreadLocalRandom.current().nextLong(); + + } while (traceIdHighLocal == 0); + long traceIdHigh = traceIdHighLocal; + long traceId = ThreadLocalRandom.current().nextLong(); + long spanId = ThreadLocalRandom.current().nextLong(); + LeaksTrackingByteBufAllocator allocator = + LeaksTrackingByteBufAllocator.instrument(ByteBufAllocator.DEFAULT); + ByteBuf byteBuf = + TracingMetadataCodec.encode128(allocator, traceIdHigh, traceId, spanId, expectedFlag); + + TracingMetadata tracingMetadata = TracingMetadataCodec.decode(byteBuf); + + Assertions.assertThat(tracingMetadata) + .matches(metadata -> !metadata.isEmpty()) + .matches(tm -> tm.traceIdHigh() == traceIdHigh) + .matches(tm -> tm.traceId() == traceId) + .matches(tm -> tm.spanId() == spanId) + .matches(tm -> !tm.hasParent()) + .matches(tm -> tm.parentId() == 0) + .matches( + tm -> { + switch (expectedFlag) { + case UNDECIDED: + return !tm.isDecided(); + case NOT_SAMPLE: + return tm.isDecided() && !tm.isSampled(); + case SAMPLE: + return tm.isDecided() && tm.isSampled(); + case DEBUG: + return tm.isDecided() && tm.isDebug(); + } + return false; + }); + Assertions.assertThat(byteBuf).matches(ReferenceCounted::release); + allocator.assertHasNoLeaks(); + } +} From a9e2954c168e6923836166da326abdc6119eb5c3 Mon Sep 17 00:00:00 2001 From: Oleh Dokuka Date: Tue, 12 May 2020 09:46:23 +0300 Subject: [PATCH 24/25] bumps version to 1.0.0 Signed-off-by: Oleh Dokuka --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 2e429e05a..c5c4fab15 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,5 +11,5 @@ # See the License for the specific language governing permissions and # limitations under the License. # -version=1.0.0-RC8 +version=1.0.0 perfBaselineVersion=1.0.0-RC7 From 8cb9e747e9b307a3c15312e460c25a8cbdb57ce5 Mon Sep 17 00:00:00 2001 From: Oleh Dokuka Date: Tue, 12 May 2020 09:54:56 +0300 Subject: [PATCH 25/25] fixes AuthMetadataCodec methods names Signed-off-by: Oleh Dokuka --- .../rsocket/metadata/AuthMetadataCodec.java | 22 +++++++++---------- .../security/AuthMetadataFlyweight.java | 16 +++++++------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/rsocket-core/src/main/java/io/rsocket/metadata/AuthMetadataCodec.java b/rsocket-core/src/main/java/io/rsocket/metadata/AuthMetadataCodec.java index 41dafb33d..d908abb3c 100644 --- a/rsocket-core/src/main/java/io/rsocket/metadata/AuthMetadataCodec.java +++ b/rsocket-core/src/main/java/io/rsocket/metadata/AuthMetadataCodec.java @@ -174,7 +174,7 @@ public static boolean isWellKnownAuthType(ByteBuf metadata) { * field's value is length or unknown auth type * @throws IllegalStateException if not enough readable bytes in the given {@link ByteBuf} */ - public static WellKnownAuthType decodeWellKnownAuthType(ByteBuf metadata) { + public static WellKnownAuthType readWellKnownAuthType(ByteBuf metadata) { if (metadata.readableBytes() < 1) { throw new IllegalStateException( "Unable to decode Well Know Auth type. Not enough readable bytes"); @@ -195,7 +195,7 @@ public static WellKnownAuthType decodeWellKnownAuthType(ByteBuf metadata) { * @param metadata * @return */ - public static CharSequence decodeCustomAuthType(ByteBuf metadata) { + public static CharSequence readCustomAuthType(ByteBuf metadata) { if (metadata.readableBytes() < 2) { throw new IllegalStateException( "Unable to decode custom Auth type. Not enough readable bytes"); @@ -226,7 +226,7 @@ public static CharSequence decodeCustomAuthType(ByteBuf metadata) { * @return sliced {@link ByteBuf} or {@link Unpooled#EMPTY_BUFFER} if no bytes readable in the * given one */ - public static ByteBuf decodePayload(ByteBuf metadata) { + public static ByteBuf readPayload(ByteBuf metadata) { if (metadata.readableBytes() == 0) { return Unpooled.EMPTY_BUFFER; } @@ -242,8 +242,8 @@ public static ByteBuf decodePayload(ByteBuf metadata) { * simpleAuthMetadata#readIndex} should be set to the username length byte * @return sliced {@link ByteBuf} or {@link Unpooled#EMPTY_BUFFER} if username length is zero */ - public static ByteBuf decodeUsername(ByteBuf simpleAuthMetadata) { - short usernameLength = decodeUsernameLength(simpleAuthMetadata); + public static ByteBuf readUsername(ByteBuf simpleAuthMetadata) { + short usernameLength = readUsernameLength(simpleAuthMetadata); if (usernameLength == 0) { return Unpooled.EMPTY_BUFFER; @@ -260,7 +260,7 @@ public static ByteBuf decodeUsername(ByteBuf simpleAuthMetadata) { * simpleAuthMetadata#readIndex} should be set to the beginning of the password bytes * @return sliced {@link ByteBuf} or {@link Unpooled#EMPTY_BUFFER} if password length is zero */ - public static ByteBuf decodePassword(ByteBuf simpleAuthMetadata) { + public static ByteBuf readPassword(ByteBuf simpleAuthMetadata) { if (simpleAuthMetadata.readableBytes() == 0) { return Unpooled.EMPTY_BUFFER; } @@ -275,8 +275,8 @@ public static ByteBuf decodePassword(ByteBuf simpleAuthMetadata) { * simpleAuthMetadata#readIndex} should be set to the username length byte * @return {@code char[]} which represents UTF-8 username */ - public static char[] decodeUsernameAsCharArray(ByteBuf simpleAuthMetadata) { - short usernameLength = decodeUsernameLength(simpleAuthMetadata); + public static char[] readUsernameAsCharArray(ByteBuf simpleAuthMetadata) { + short usernameLength = readUsernameLength(simpleAuthMetadata); if (usernameLength == 0) { return EMPTY_CHARS_ARRAY; @@ -293,7 +293,7 @@ public static char[] decodeUsernameAsCharArray(ByteBuf simpleAuthMetadata) { * simpleAuthMetadata#readIndex} should be set to the beginning of the password bytes * @return {@code char[]} which represents UTF-8 password */ - public static char[] decodePasswordAsCharArray(ByteBuf simpleAuthMetadata) { + public static char[] readPasswordAsCharArray(ByteBuf simpleAuthMetadata) { if (simpleAuthMetadata.readableBytes() == 0) { return EMPTY_CHARS_ARRAY; } @@ -309,7 +309,7 @@ public static char[] decodePasswordAsCharArray(ByteBuf simpleAuthMetadata) { * simpleAuthMetadata#readIndex} should be set to the beginning of the password bytes * @return {@code char[]} which represents UTF-8 password */ - public static char[] decodeBearerTokenAsCharArray(ByteBuf bearerAuthMetadata) { + public static char[] readBearerTokenAsCharArray(ByteBuf bearerAuthMetadata) { if (bearerAuthMetadata.readableBytes() == 0) { return EMPTY_CHARS_ARRAY; } @@ -317,7 +317,7 @@ public static char[] decodeBearerTokenAsCharArray(ByteBuf bearerAuthMetadata) { return CharByteBufUtil.readUtf8(bearerAuthMetadata, bearerAuthMetadata.readableBytes()); } - private static short decodeUsernameLength(ByteBuf simpleAuthMetadata) { + private static short readUsernameLength(ByteBuf simpleAuthMetadata) { if (simpleAuthMetadata.readableBytes() < 1) { throw new IllegalStateException( "Unable to decode custom username. Not enough readable bytes"); diff --git a/rsocket-core/src/main/java/io/rsocket/metadata/security/AuthMetadataFlyweight.java b/rsocket-core/src/main/java/io/rsocket/metadata/security/AuthMetadataFlyweight.java index fd990d273..e1a8ba449 100644 --- a/rsocket-core/src/main/java/io/rsocket/metadata/security/AuthMetadataFlyweight.java +++ b/rsocket-core/src/main/java/io/rsocket/metadata/security/AuthMetadataFlyweight.java @@ -107,7 +107,7 @@ public static boolean isWellKnownAuthType(ByteBuf metadata) { * @throws IllegalStateException if not enough readable bytes in the given {@link ByteBuf} */ public static WellKnownAuthType decodeWellKnownAuthType(ByteBuf metadata) { - return WellKnownAuthType.cast(AuthMetadataCodec.decodeWellKnownAuthType(metadata)); + return WellKnownAuthType.cast(AuthMetadataCodec.readWellKnownAuthType(metadata)); } /** @@ -117,7 +117,7 @@ public static WellKnownAuthType decodeWellKnownAuthType(ByteBuf metadata) { * @return */ public static CharSequence decodeCustomAuthType(ByteBuf metadata) { - return AuthMetadataCodec.decodeCustomAuthType(metadata); + return AuthMetadataCodec.readCustomAuthType(metadata); } /** @@ -130,7 +130,7 @@ public static CharSequence decodeCustomAuthType(ByteBuf metadata) { * given one */ public static ByteBuf decodePayload(ByteBuf metadata) { - return AuthMetadataCodec.decodePayload(metadata); + return AuthMetadataCodec.readPayload(metadata); } /** @@ -142,7 +142,7 @@ public static ByteBuf decodePayload(ByteBuf metadata) { * @return sliced {@link ByteBuf} or {@link Unpooled#EMPTY_BUFFER} if username length is zero */ public static ByteBuf decodeUsername(ByteBuf simpleAuthMetadata) { - return AuthMetadataCodec.decodeUsername(simpleAuthMetadata); + return AuthMetadataCodec.readUsername(simpleAuthMetadata); } /** @@ -154,7 +154,7 @@ public static ByteBuf decodeUsername(ByteBuf simpleAuthMetadata) { * @return sliced {@link ByteBuf} or {@link Unpooled#EMPTY_BUFFER} if password length is zero */ public static ByteBuf decodePassword(ByteBuf simpleAuthMetadata) { - return AuthMetadataCodec.decodePassword(simpleAuthMetadata); + return AuthMetadataCodec.readPassword(simpleAuthMetadata); } /** * Read up to 257 {@code bytes} from the given {@link ByteBuf} where the first byte is username @@ -165,7 +165,7 @@ public static ByteBuf decodePassword(ByteBuf simpleAuthMetadata) { * @return {@code char[]} which represents UTF-8 username */ public static char[] decodeUsernameAsCharArray(ByteBuf simpleAuthMetadata) { - return AuthMetadataCodec.decodeUsernameAsCharArray(simpleAuthMetadata); + return AuthMetadataCodec.readUsernameAsCharArray(simpleAuthMetadata); } /** @@ -177,7 +177,7 @@ public static char[] decodeUsernameAsCharArray(ByteBuf simpleAuthMetadata) { * @return {@code char[]} which represents UTF-8 password */ public static char[] decodePasswordAsCharArray(ByteBuf simpleAuthMetadata) { - return AuthMetadataCodec.decodePasswordAsCharArray(simpleAuthMetadata); + return AuthMetadataCodec.readPasswordAsCharArray(simpleAuthMetadata); } /** @@ -189,6 +189,6 @@ public static char[] decodePasswordAsCharArray(ByteBuf simpleAuthMetadata) { * @return {@code char[]} which represents UTF-8 password */ public static char[] decodeBearerTokenAsCharArray(ByteBuf bearerAuthMetadata) { - return AuthMetadataCodec.decodeBearerTokenAsCharArray(bearerAuthMetadata); + return AuthMetadataCodec.readBearerTokenAsCharArray(bearerAuthMetadata); } }