com.datastax.driver.core.Message Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dse-java-driver-core Show documentation
Show all versions of dse-java-driver-core Show documentation
A driver for DataStax Enterprise (DSE)
and Apache Cassandra 1.2+ clusters that works exclusively with the
Cassandra Query Language version 3 (CQL3) and Cassandra's binary protocol,
supporting DSE-specific features such as geospatial types, DSE Graph and DSE authentication.
/*
* Copyright DataStax, Inc.
*
* This software can be used solely with DataStax Enterprise. Please consult the license at
* http://www.datastax.com/terms/datastax-dse-driver-license-terms
*/
package com.datastax.driver.core;
import com.datastax.driver.core.exceptions.DriverInternalError;
import com.datastax.driver.core.exceptions.UnsupportedFeatureException;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.handler.codec.MessageToMessageEncoder;
import io.netty.util.AttributeKey;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** A message from the CQL binary protocol. */
abstract class Message {
protected static final Logger logger = LoggerFactory.getLogger(Message.class);
static AttributeKey CODEC_REGISTRY_ATTRIBUTE_KEY =
AttributeKey.valueOf("com.datastax.driver.core.CodecRegistry");
interface Coder {
void encode(R request, ByteBuf dest, ProtocolVersion version);
int encodedSize(R request, ProtocolVersion version);
}
interface Decoder {
R decode(ByteBuf body, ProtocolVersion version, CodecRegistry codecRegistry);
}
private volatile int streamId = -1;
/**
* A generic key-value custom payload. Custom payloads are simply ignored by the default
* QueryHandler implementation server-side.
*
* @since Protocol V4
*/
private volatile Map customPayload;
protected Message() {}
Message setStreamId(int streamId) {
this.streamId = streamId;
return this;
}
int getStreamId() {
return streamId;
}
Map getCustomPayload() {
return customPayload;
}
Message setCustomPayload(Map customPayload) {
this.customPayload = customPayload;
return this;
}
abstract static class Request extends Message {
enum Type {
// public requests
STARTUP(1, Requests.Startup.coder),
CREDENTIALS(4, Requests.Credentials.coder),
OPTIONS(5, Requests.Options.coder),
QUERY(7, Requests.Query.coder),
PREPARE(9, Requests.Prepare.coder),
EXECUTE(10, Requests.Execute.coder),
REGISTER(11, Requests.Register.coder),
BATCH(13, Requests.Batch.coder),
AUTH_RESPONSE(15, Requests.AuthResponse.coder),
// private requests
REVISE_REQUEST(255, Requests.ReviseRequest.coder);
final int opcode;
final Coder> coder;
Type(int opcode, Coder> coder) {
this.opcode = opcode;
this.coder = coder;
}
}
final Type type;
private final boolean tracingRequested;
protected Request(Type type) {
this(type, false);
}
protected Request(Type type, boolean tracingRequested) {
this.type = type;
this.tracingRequested = tracingRequested;
}
@Override
Request setStreamId(int streamId) {
// JAVA-1179: defensively guard against reusing the same Request object twice.
// If no streamId was ever set we can use this object directly, otherwise make a copy.
if (getStreamId() < 0) return (Request) super.setStreamId(streamId);
else {
Request copy = this.copy();
copy.setStreamId(streamId);
return copy;
}
}
boolean isTracingRequested() {
return tracingRequested;
}
ConsistencyLevel consistency() {
switch (this.type) {
case QUERY:
return ((Requests.Query) this).options.consistency;
case EXECUTE:
return ((Requests.Execute) this).options.consistency;
case BATCH:
return ((Requests.Batch) this).options.consistency;
default:
return null;
}
}
ConsistencyLevel serialConsistency() {
switch (this.type) {
case QUERY:
return ((Requests.Query) this).options.serialConsistency;
case EXECUTE:
return ((Requests.Execute) this).options.serialConsistency;
case BATCH:
return ((Requests.Batch) this).options.serialConsistency;
default:
return null;
}
}
long defaultTimestamp() {
switch (this.type) {
case QUERY:
return ((Requests.Query) this).options.defaultTimestamp;
case EXECUTE:
return ((Requests.Execute) this).options.defaultTimestamp;
case BATCH:
return ((Requests.Batch) this).options.defaultTimestamp;
default:
return 0;
}
}
ByteBuffer pagingState() {
switch (this.type) {
case QUERY:
return ((Requests.Query) this).options.pagingState;
case EXECUTE:
return ((Requests.Execute) this).options.pagingState;
default:
return null;
}
}
Requests.QueryProtocolOptions options() {
switch (this.type) {
case QUERY:
return ((Requests.Query) this).options;
case EXECUTE:
return ((Requests.Execute) this).options;
default:
return null;
}
}
Request copy() {
Request request = copyInternal();
request.setCustomPayload(this.getCustomPayload());
return request;
}
protected abstract Request copyInternal();
Request copy(ConsistencyLevel newConsistencyLevel) {
Request request = copyInternal(newConsistencyLevel);
request.setCustomPayload(this.getCustomPayload());
return request;
}
protected Request copyInternal(ConsistencyLevel newConsistencyLevel) {
throw new UnsupportedOperationException();
}
}
abstract static class Response extends Message {
enum Type {
ERROR(0, Responses.Error.decoder),
READY(2, Responses.Ready.decoder),
AUTHENTICATE(3, Responses.Authenticate.decoder),
SUPPORTED(6, Responses.Supported.decoder),
RESULT(8, Responses.Result.decoder),
EVENT(12, Responses.Event.decoder),
AUTH_CHALLENGE(14, Responses.AuthChallenge.decoder),
AUTH_SUCCESS(16, Responses.AuthSuccess.decoder);
final int opcode;
final Decoder> decoder;
private static final Type[] opcodeIdx;
static {
int maxOpcode = -1;
for (Type type : Type.values()) maxOpcode = Math.max(maxOpcode, type.opcode);
opcodeIdx = new Type[maxOpcode + 1];
for (Type type : Type.values()) {
if (opcodeIdx[type.opcode] != null) throw new IllegalStateException("Duplicate opcode");
opcodeIdx[type.opcode] = type;
}
}
Type(int opcode, Decoder> decoder) {
this.opcode = opcode;
this.decoder = decoder;
}
static Type fromOpcode(int opcode) {
if (opcode < 0 || opcode >= opcodeIdx.length)
throw new DriverInternalError(String.format("Unknown response opcode %d", opcode));
Type t = opcodeIdx[opcode];
if (t == null)
throw new DriverInternalError(String.format("Unknown response opcode %d", opcode));
return t;
}
}
final Type type;
protected volatile UUID tracingId;
protected volatile List warnings;
protected Response(Type type) {
this.type = type;
}
Response setTracingId(UUID tracingId) {
this.tracingId = tracingId;
return this;
}
UUID getTracingId() {
return tracingId;
}
Response setWarnings(List warnings) {
this.warnings = warnings;
return this;
}
}
@ChannelHandler.Sharable
static class ProtocolDecoder extends MessageToMessageDecoder {
@Override
protected void decode(ChannelHandlerContext ctx, Frame frame, List