/* * Copyright 2015 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.atomix.catalyst.transport.netty; import io.atomix.catalyst.buffer.Buffer; import io.atomix.catalyst.buffer.BufferOutput; import io.atomix.catalyst.buffer.Bytes; import io.netty.buffer.ByteBuf; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; /** * Byte buffer output. * * @author <a href="http://github.com/kuujo>Jordan Halterman</a> */ final class ByteBufOutput implements BufferOutput<ByteBufOutput> { ByteBuf buffer; /** * Sets the underlying byte buffer. */ ByteBufOutput setByteBuf(ByteBuf buffer) { this.buffer = buffer; return this; } /** * Ensures that {@code size} bytes can be written to the buffer. */ private void checkWrite(int size) { // If the buffer does not have enough bytes remaining, attempt to discard some of the read bytes. // It is possible that the buffer could discard 0 bytes, so we ensure the buffer is writable after // discarding some read bytes, and if not discard all read bytes. if (buffer.writerIndex() + size > buffer.maxCapacity()) { buffer.discardSomeReadBytes(); if (buffer.writerIndex() + size > buffer.maxCapacity()) { buffer.discardReadBytes(); } } } @Override public ByteBufOutput write(Buffer buffer) { int size = Math.min((int) buffer.remaining(), this.buffer.writableBytes()); checkWrite(size); byte[] bytes = new byte[size]; buffer.read(bytes); this.buffer.writeBytes(bytes); return this; } @Override public ByteBufOutput write(Bytes bytes) { int size = Math.min((int) bytes.size(), buffer.writableBytes()); checkWrite(size); byte[] b = new byte[size]; bytes.read(0, b, 0, b.length); buffer.writeBytes(b); return this; } @Override public ByteBufOutput write(byte[] bytes) { checkWrite(bytes.length); buffer.writeBytes(bytes); return this; } @Override public ByteBufOutput write(Bytes bytes, long offset, long length) { int size = Math.min((int) bytes.size(), (int) length); checkWrite(size); byte[] b = new byte[size]; bytes.read(offset, b, 0, b.length); buffer.writeBytes(b); return this; } @Override public ByteBufOutput write(byte[] bytes, long offset, long length) { checkWrite((int) length); buffer.writeBytes(bytes, (int) offset, (int) length); return this; } @Override public ByteBufOutput writeByte(int b) { checkWrite(Bytes.BYTE); buffer.writeByte(b); return this; } @Override public ByteBufOutput writeUnsignedByte(int b) { checkWrite(Bytes.BYTE); buffer.writeByte(b); return this; } @Override public ByteBufOutput writeChar(char c) { checkWrite(Bytes.CHARACTER); buffer.writeChar(c); return this; } @Override public ByteBufOutput writeShort(short s) { checkWrite(Bytes.SHORT); buffer.writeShort(s); return this; } @Override public ByteBufOutput writeUnsignedShort(int s) { checkWrite(Bytes.SHORT); buffer.writeShort(s); return this; } @Override public ByteBufOutput writeInt(int i) { checkWrite(Bytes.INTEGER); buffer.writeInt(i); return this; } @Override public ByteBufOutput writeUnsignedInt(long i) { checkWrite(Bytes.INTEGER); buffer.writeInt((int) i); return this; } @Override public ByteBufOutput writeMedium(int m) { checkWrite(Bytes.MEDIUM); buffer.writeMedium(m); return this; } @Override public ByteBufOutput writeUnsignedMedium(int m) { checkWrite(Bytes.MEDIUM); buffer.writeMedium(m); return this; } @Override public ByteBufOutput writeLong(long l) { checkWrite(Bytes.LONG); buffer.writeLong(l); return this; } @Override public ByteBufOutput writeFloat(float f) { checkWrite(Bytes.FLOAT); buffer.writeFloat(f); return this; } @Override public ByteBufOutput writeDouble(double d) { checkWrite(Bytes.DOUBLE); buffer.writeDouble(d); return this; } @Override public ByteBufOutput writeBoolean(boolean b) { checkWrite(Bytes.BOOLEAN); buffer.writeBoolean(b); return this; } @Override public ByteBufOutput writeString(String s) { return writeString(s, Charset.defaultCharset()); } @Override public ByteBufOutput writeString(String s, Charset charset) { if (s == null) { return writeBoolean(Boolean.FALSE); } else { byte[] bytes = s.getBytes(charset); writeBoolean(Boolean.TRUE); return writeUnsignedShort(bytes.length) .write(bytes, 0, bytes.length); } } @Override public ByteBufOutput writeUTF8(String s) { return writeString(s, StandardCharsets.UTF_8); } @Override public ByteBufOutput flush() { return this; } @Override public void close() { } }