package cassandra.protocol.internal; import cassandra.cql.type.CQL3Type; import io.netty.buffer.ByteBuf; import io.netty.util.CharsetUtil; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.util.EnumSet; import java.util.List; import java.util.Map; import java.util.UUID; public class MessageOutputStream { private final ByteBuf buffer; public MessageOutputStream(ByteBuf buffer) { this.buffer = buffer; } public void writeMessage(Message value) { writeInt32(value.getApproximateSize()); value.writeTo(this); } public void writeDouble(double value) { buffer.writeDouble(value); } public void writeFloat(float value) { buffer.writeFloat(value); } public void writeInt64(long value) { buffer.writeLong(value); } public void writeInt32(int value) { buffer.writeInt(value); } public void writeInt16(int value) { buffer.writeShort(value); } public void writeInt8(int value) { buffer.writeByte(value); } public void writeBool(boolean value) { if (value) { writeInt8(1); } else { writeInt8(0); } } public <T extends Enum<T>> void writeEnumSet8(EnumSet<T> value) { int flags = 0; for (T v : value) { flags |= 1 << v.ordinal(); } writeInt8(flags); } public <T extends Enum<T>> void writeEnumSet32(EnumSet<T> value) { int flags = 0; for (T v : value) { flags |= 1 << v.ordinal(); } writeInt32(flags); } public <T extends Enum<T>> void writeEnum(T value) { writeString(value.toString()); } public void writeCQLType(CQL3Type value) { // TODO } public void writeUUID(UUID value) { writeInt64(value.getMostSignificantBits()); writeInt64(value.getLeastSignificantBits()); } public void writeInet(InetSocketAddress value) { byte[] bytes = value.getAddress().getAddress(); writeInt8(bytes.length); writeRawBytes(bytes); writeInt32(value.getPort()); } public void writeStringToStringListMap(Map<String, List<String>> value) { writeInt16(value.size()); for (Map.Entry<String, List<String>> entry : value.entrySet()) { writeString(entry.getKey()); writeStringList(entry.getValue()); } } public void writeStringMap(Map<String, String> value) { writeInt16(value.size()); for (Map.Entry<String, String> entry : value.entrySet()) { writeString(entry.getKey()); writeString(entry.getValue()); } } public void writeLongString(String value) { byte[] bytes = value.getBytes(CharsetUtil.UTF_8); writeInt32(bytes.length); writeRawBytes(bytes); } public void writeStringList(List<String> value) { writeInt16(value.size()); for (String v : value) { writeString(v); } } public void writeString(String value) { byte[] bytes = value.getBytes(CharsetUtil.UTF_8); writeInt16(bytes.length); writeRawBytes(bytes); } public void writeValueList(List<ByteBuffer> value) { writeInt16(value.size()); for (ByteBuffer v : value) { writeValue(v); } } public void writeValueArray(ByteBuffer[] value) { writeInt16(value.length); for (ByteBuffer v : value) { writeValue(v); } } public void writeValue(ByteBuffer value) { if (value == null) { writeInt32(-1); return; } writeInt32(value.remaining()); writeRawBytes(value.duplicate()); } public void writeValue(byte[] value) { if (value == null) { writeInt32(-1); return; } writeInt32(value.length); writeRawBytes(value); } public void writeBytes(ByteBuffer value) { writeInt16(value.remaining()); writeRawBytes(value); } public void writeBytes(byte[] value) { writeInt16(value.length); writeRawBytes(value); } public void writeRawBytes(ByteBuffer value) { buffer.writeBytes(value); } public void writeRawBytes(byte[] value) { buffer.writeBytes(value); } public ByteBuf buffer() { return buffer; } public boolean close() { return buffer != null && buffer.refCnt() > 0 && buffer.release(); } public static <T extends Enum<T>> int computeEnumSize(T value) { return computeStringSize(value.toString()); } public static int computeCQLTypeSize(CQL3Type value) { int size = 2; switch (value.name()) { case CUSTOM: return size + computeStringSize(value.customClassName()); case LIST: case SET: return size + computeCQLTypeSize(value.typeArguments().get(0)); case MAP: size += computeCQLTypeSize(value.typeArguments().get(0)); size += computeCQLTypeSize(value.typeArguments().get(1)); return size; default: return size; } } public static int computeInetSize(InetSocketAddress value) { byte[] bytes = value.getAddress().getAddress(); int size = 1; size += bytes.length; size += 4; return size; } public static int computeStringToStringListMapSize(Map<String, List<String>> value) { int size = 2; for (Map.Entry<String, List<String>> entry : value.entrySet()) { size += computeStringSize(entry.getKey()); size += computeStringListSize(entry.getValue()); } return size; } public static int computeStringMapSize(Map<String, String> value) { int size = 2; for (Map.Entry<String, String> entry : value.entrySet()) { size += computeStringSize(entry.getKey()); size += computeStringSize(entry.getValue()); } return size; } public static int computeLongStringSize(String value) { byte[] bytes = value.getBytes(CharsetUtil.UTF_8); return 4 + bytes.length; } public static int computeStringListSize(List<String> value) { int size = 2; for (String v : value) { size += computeStringSize(v); } return size; } public static int computeStringSize(String value) { byte[] bytes = value.getBytes(CharsetUtil.UTF_8); return 2 + bytes.length; } public static int computeValueListSize(List<ByteBuffer> value) { int size = 2; for (ByteBuffer v : value) { size += computeValueSize(v); } return size; } public static int computeValueArraySize(ByteBuffer[] value) { int size = 2; for (ByteBuffer v : value) { size += computeValueSize(v); } return size; } public static int computeValueSize(ByteBuffer value) { return 4 + (value == null ? 0 : value.remaining()); } public static int computeValueSize(byte[] value) { return 4 + (value == null ? 0 : value.length); } public static int computeBytesSize(byte[] value) { return 2 + (value == null ? 0 : value.length); } }