Package com.datastax.driver.core

Source Code of com.datastax.driver.core.Responses$Event

/*
*      Copyright (C) 2012-2014 DataStax Inc.
*
*   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 com.datastax.driver.core;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;

import org.jboss.netty.buffer.ChannelBuffer;

import com.datastax.driver.core.ProtocolEvent.SchemaChange;
import com.datastax.driver.core.ProtocolEvent.SchemaChange.Change;
import com.datastax.driver.core.ProtocolEvent.SchemaChange.Target;
import com.datastax.driver.core.Responses.Result.Rows.Metadata;
import com.datastax.driver.core.exceptions.*;
import com.datastax.driver.core.utils.Bytes;

class Responses {

    private Responses() {}

    public static class Error extends Message.Response {

        public static final Message.Decoder<Error> decoder = new Message.Decoder<Error>() {
            @Override
            public Error decode(ChannelBuffer body, ProtocolVersion version) {
                ExceptionCode code = ExceptionCode.fromValue(body.readInt());
                String msg = CBUtil.readString(body);
                Object infos = null;
                switch (code) {
                    case UNAVAILABLE:
                        ConsistencyLevel clu = CBUtil.readConsistencyLevel(body);
                        int required = body.readInt();
                        int alive = body.readInt();
                        infos = new UnavailableException(clu, required, alive);
                        break;
                    case WRITE_TIMEOUT:
                    case READ_TIMEOUT:
                        ConsistencyLevel clt = CBUtil.readConsistencyLevel(body);
                        int received = body.readInt();
                        int blockFor = body.readInt();
                        if (code == ExceptionCode.WRITE_TIMEOUT) {
                            WriteType writeType = Enum.valueOf(WriteType.class, CBUtil.readString(body));
                            infos = new WriteTimeoutException(clt, writeType, received, blockFor);
                        } else {
                            byte dataPresent = body.readByte();
                            infos = new ReadTimeoutException(clt, received, blockFor, dataPresent != 0);
                        }
                        break;
                    case UNPREPARED:
                        infos = MD5Digest.wrap(CBUtil.readBytes(body));
                        break;
                    case ALREADY_EXISTS:
                        String ksName = CBUtil.readString(body);
                        String cfName = CBUtil.readString(body);
                        infos = new AlreadyExistsException(ksName, cfName);
                        break;
                }
                return new Error(version, code, msg, infos);
            }
        };

        public final ProtocolVersion serverProtocolVersion;
        public final ExceptionCode code;
        public final String message;
        public final Object infos; // can be null

        private Error(ProtocolVersion serverProtocolVersion, ExceptionCode code, String message, Object infos) {
            super(Message.Response.Type.ERROR);
            this.serverProtocolVersion = serverProtocolVersion;
            this.code = code;
            this.message = message;
            this.infos = infos;
        }

        public DriverException asException(InetSocketAddress host) {
            switch (code) {
                case SERVER_ERROR:     return new DriverInternalError(String.format("An unexpected error occurred server side on %s: %s", host, message));
                case PROTOCOL_ERROR:   return new DriverInternalError("An unexpected protocol error occurred. This is a bug in this library, please report: " + message);
                case BAD_CREDENTIALS:  return new AuthenticationException(host, message);
                case UNAVAILABLE:      return ((UnavailableException)infos).copy(); // We copy to have a nice stack trace
                case OVERLOADED:       return new DriverInternalError(String.format("Queried host (%s) was overloaded; this shouldn't happen, another node should have been tried", host));
                case IS_BOOTSTRAPPING: return new DriverInternalError(String.format("Queried host (%s) was bootstrapping; this shouldn't happen, another node should have been tried", host));
                case TRUNCATE_ERROR:   return new TruncateException(message);
                case WRITE_TIMEOUT:    return ((WriteTimeoutException)infos).copy();
                case READ_TIMEOUT:     return ((ReadTimeoutException)infos).copy();
                case SYNTAX_ERROR:     return new SyntaxError(message);
                case UNAUTHORIZED:     return new UnauthorizedException(message);
                case INVALID:          return new InvalidQueryException(message);
                case CONFIG_ERROR:     return new InvalidConfigurationInQueryException(message);
                case ALREADY_EXISTS:   return ((AlreadyExistsException)infos).copy();
                case UNPREPARED:       return new DriverInternalError(String.format("A prepared query was submitted on %s but was not known of that node; this shouldn't happen, the query should have been re-prepared", host));
                default:               return new DriverInternalError(String.format("Unknown protocol error code %s returned by %s. The error message was: %s", code, host, message));
            }
        }

        @Override
        public String toString() {
            return "ERROR " + code + ": " + message;
        }
    }

    public static class Ready extends Message.Response {

        public static final Message.Decoder<Ready> decoder = new Message.Decoder<Ready>() {
            public Ready decode(ChannelBuffer body, ProtocolVersion version) {
                // TODO: Would it be cool to return a singleton? Check we don't need to
                // set the streamId or something
                return new Ready();
            }
        };

        public Ready() {
            super(Message.Response.Type.READY);
        }

        @Override
        public String toString() {
            return "READY";
        }
    }

    public static class Authenticate extends Message.Response {

        public static final Message.Decoder<Authenticate> decoder = new Message.Decoder<Authenticate>() {
            public Authenticate decode(ChannelBuffer body, ProtocolVersion version) {
                String authenticator = CBUtil.readString(body);
                return new Authenticate(authenticator);
            }
        };

        public final String authenticator;

        public Authenticate(String authenticator) {
            super(Message.Response.Type.AUTHENTICATE);
            this.authenticator = authenticator;
        }

        @Override
        public String toString() {
            return "AUTHENTICATE " + authenticator;
        }
    }

    public static class Supported extends Message.Response {

        public static final Message.Decoder<Supported> decoder = new Message.Decoder<Supported>() {
            public Supported decode(ChannelBuffer body, ProtocolVersion version) {
                return new Supported(CBUtil.readStringToStringListMap(body));
            }
        };

        public final Map<String, List<String>> supported;
        public final Set<ProtocolOptions.Compression> supportedCompressions = EnumSet.noneOf(ProtocolOptions.Compression.class);

        public Supported(Map<String, List<String>> supported) {
            super(Message.Response.Type.SUPPORTED);
            this.supported = supported;

            parseCompressions();
        }

        private void parseCompressions() {
            List<String> compList = supported.get(Requests.Startup.COMPRESSION_OPTION);
            if (compList == null)
                return;

            for (String compStr : compList) {
                ProtocolOptions.Compression compr = ProtocolOptions.Compression.fromString(compStr);
                if (compr != null)
                    supportedCompressions.add(compr);
            }
        }

        @Override
        public String toString() {
            return "SUPPORTED " + supported;
        }
    }

    public static abstract class Result extends Message.Response {

        public static final Message.Decoder<Result> decoder = new Message.Decoder<Result>() {
            public Result decode(ChannelBuffer body, ProtocolVersion version) {
                Kind kind = Kind.fromId(body.readInt());
                return kind.subDecoder.decode(body, version);
            }
        };

        public enum Kind {
            VOID         (1, Void.subcodec),
            ROWS         (2, Rows.subcodec),
            SET_KEYSPACE (3, SetKeyspace.subcodec),
            PREPARED     (4, Prepared.subcodec),
            SCHEMA_CHANGE(5, SchemaChange.subcodec);

            private final int id;
            final Message.Decoder<Result> subDecoder;

            private static final Kind[] ids;
            static {
                int maxId = -1;
                for (Kind k : Kind.values())
                    maxId = Math.max(maxId, k.id);
                ids = new Kind[maxId + 1];
                for (Kind k : Kind.values()) {
                    if (ids[k.id] != null)
                        throw new IllegalStateException("Duplicate kind id");
                    ids[k.id] = k;
                }
            }

            private Kind(int id, Message.Decoder<Result> subDecoder) {
                this.id = id;
                this.subDecoder = subDecoder;
            }

            public static Kind fromId(int id) {
                Kind k = ids[id];
                if (k == null)
                    throw new DriverInternalError(String.format("Unknown kind id %d in RESULT message", id));
                return k;
            }
        }

        public final Kind kind;

        protected Result(Kind kind) {
            super(Message.Response.Type.RESULT);
            this.kind = kind;
        }

        public static class Void extends Result {
            // Even though we have no specific information here, don't make a
            // singleton since as each message it has in fact a streamid and connection.
            public Void() {
                super(Kind.VOID);
            }

            public static final Message.Decoder<Result> subcodec = new Message.Decoder<Result>() {
                public Result decode(ChannelBuffer body, ProtocolVersion version) {
                    return new Void();
                }
            };

            @Override
            public String toString() {
                return "EMPTY RESULT";
            }
        }

        public static class SetKeyspace extends Result {
            public final String keyspace;

            private SetKeyspace(String keyspace) {
                super(Kind.SET_KEYSPACE);
                this.keyspace = keyspace;
            }

            public static final Message.Decoder<Result> subcodec = new Message.Decoder<Result>() {
                public Result decode(ChannelBuffer body, ProtocolVersion version) {
                    return new SetKeyspace(CBUtil.readString(body));
                }
            };

            @Override
            public String toString() {
                return "RESULT set keyspace " + keyspace;
            }
        }

        public static class Rows extends Result {

            public static class Metadata {

                private static enum Flag
                {
                    // The order of that enum matters!!
                    GLOBAL_TABLES_SPEC,
                    HAS_MORE_PAGES,
                    NO_METADATA;

                    public static EnumSet<Flag> deserialize(int flags) {
                        EnumSet<Flag> set = EnumSet.noneOf(Flag.class);
                        Flag[] values = Flag.values();
                        for (int n = 0; n < values.length; n++) {
                            if ((flags & (1 << n)) != 0)
                                set.add(values[n]);
                        }
                        return set;
                    }

                    public static int serialize(EnumSet<Flag> flags) {
                        int i = 0;
                        for (Flag flag : flags)
                            i |= 1 << flag.ordinal();
                        return i;
                    }
                }

                static final Metadata EMPTY = new Metadata(0, null, null);

                public final int columnCount;
                public final ColumnDefinitions columns; // Can be null if no metadata was asked by the query
                public final ByteBuffer pagingState;

                private Metadata(int columnCount, ColumnDefinitions columns, ByteBuffer pagingState) {
                    this.columnCount = columnCount;
                    this.columns = columns;
                    this.pagingState = pagingState;
                }

                public static Metadata decode(ChannelBuffer body) {

                    // flags & column count
                    EnumSet<Flag> flags = Flag.deserialize(body.readInt());
                    int columnCount = body.readInt();

                    ByteBuffer state = null;
                    if (flags.contains(Flag.HAS_MORE_PAGES))
                        state = CBUtil.readValue(body);

                    if (flags.contains(Flag.NO_METADATA))
                        return new Metadata(columnCount, null, state);

                    boolean globalTablesSpec = flags.contains(Flag.GLOBAL_TABLES_SPEC);

                    String globalKsName = null;
                    String globalCfName = null;
                    if (globalTablesSpec) {
                        globalKsName = CBUtil.readString(body);
                        globalCfName = CBUtil.readString(body);
                    }

                    // metadata (names/types)
                    ColumnDefinitions.Definition[] defs = new ColumnDefinitions.Definition[columnCount];
                    for (int i = 0; i < columnCount; i++) {
                        String ksName = globalTablesSpec ? globalKsName : CBUtil.readString(body);
                        String cfName = globalTablesSpec ? globalCfName : CBUtil.readString(body);
                        String name = CBUtil.readString(body);
                        DataType type = DataType.decode(body);
                        defs[i] = new ColumnDefinitions.Definition(ksName, cfName, name, type);
                    }

                    return new Metadata(columnCount, new ColumnDefinitions(defs), state);
                }

                @Override
                public String toString() {
                    StringBuilder sb = new StringBuilder();

                    if (columns == null) {
                        sb.append('[').append(columnCount).append(" columns]");
                    } else {
                        for (ColumnDefinitions.Definition column : columns) {
                            sb.append('[').append(column.getName());
                            sb.append(" (").append(column.getType()).append(")]");
                        }
                    }
                    if (pagingState != null)
                        sb.append(" (to be continued)");
                    return sb.toString();
                }
            }

            public static final Message.Decoder<Result> subcodec = new Message.Decoder<Result>() {
                public Result decode(ChannelBuffer body, ProtocolVersion version) {

                    Metadata metadata = Metadata.decode(body);

                    int rowCount = body.readInt();
                    int columnCount = metadata.columnCount;

                    Queue<List<ByteBuffer>> data = new ArrayDeque<List<ByteBuffer>>(rowCount);
                    for (int i = 0; i < rowCount; i++) {
                        List<ByteBuffer> row = new ArrayList<ByteBuffer>(columnCount);
                        for (int j = 0; j < columnCount; j++)
                            row.add(CBUtil.readValue(body));
                        data.add(row);
                    }

                    return new Rows(metadata, data);
                }
            };

            public final Metadata metadata;
            public final Queue<List<ByteBuffer>> data;

            private Rows(Metadata metadata, Queue<List<ByteBuffer>> data) {
                super(Kind.ROWS);
                this.metadata = metadata;
                this.data = data;
            }

            @Override
            public String toString() {
                StringBuilder sb = new StringBuilder();
                sb.append("ROWS ").append(metadata).append('\n');
                for (List<ByteBuffer> row : data) {
                    for (int i = 0; i < row.size(); i++) {
                        ByteBuffer v = row.get(i);
                        if (v == null) {
                            sb.append(" | null");
                        } else {
                            sb.append(" | ");
                            if (metadata.columns == null) {
                                sb.append(Bytes.toHexString(v));
                            } else {
                                // We don't have the protocol version available and it's a pain to change
                                // everything to get it when this method is only ever call for debugging.
                                // So trying v3 and falling back to v2, which is ugly but good enough for now.
                                try {
                                    sb.append(metadata.columns.getType(i).deserialize(v, ProtocolVersion.V3));
                                } catch (IllegalArgumentException e) {
                                    sb.append(metadata.columns.getType(i).deserialize(v, ProtocolVersion.V2));
                                }
                            }
                        }
                    }
                    sb.append('\n');
                }
                sb.append("---");
                return sb.toString();
            }
        }

        public static class Prepared extends Result {

            public static final Message.Decoder<Result> subcodec = new Message.Decoder<Result>() {
                public Result decode(ChannelBuffer body, ProtocolVersion version) {
                    MD5Digest id = MD5Digest.wrap(CBUtil.readBytes(body));
                    Rows.Metadata metadata = Rows.Metadata.decode(body);
                    Rows.Metadata resultMetadata = decodeResultMetadata(body, version);
                    return new Prepared(id, metadata, resultMetadata);
                }

                private Metadata decodeResultMetadata(ChannelBuffer body, ProtocolVersion version) {
                    switch (version) {
                        case V1:
                            return Rows.Metadata.EMPTY;
                        case V2:
                        case V3:
                            return Rows.Metadata.decode(body);
                        default:
                            throw version.unsupported();
                    }
                }
            };

            public final MD5Digest statementId;
            public final Rows.Metadata metadata;
            public final Rows.Metadata resultMetadata;

            private Prepared(MD5Digest statementId, Rows.Metadata metadata, Rows.Metadata resultMetadata) {
                super(Kind.PREPARED);
                this.statementId = statementId;
                this.metadata = metadata;
                this.resultMetadata = resultMetadata;
            }

            @Override
            public String toString() {
                return "RESULT PREPARED " + statementId + ' ' + metadata + " (resultMetadata=" + resultMetadata + ')';
            }
        }

        public static class SchemaChange extends Result {

            public enum Change { CREATED, UPDATED, DROPPED }
            public enum Target { KEYSPACE, TABLE, TYPE }

            public final Change change;
            public final Target target;
            public final String keyspace;
            public final String name;

            public static final Message.Decoder<Result> subcodec = new Message.Decoder<Result>() {
                public Result decode(ChannelBuffer body, ProtocolVersion version)
                {
                    // Note: the CREATE KEYSPACE/TABLE/TYPE SCHEMA_CHANGE response is different from the SCHEMA_CHANGE EVENT type
                    Change change;
                    Target target;
                    String keyspace, name;
                    switch (version) {
                        case V1:
                        case V2:
                            change = CBUtil.readEnumValue(Change.class, body);
                            keyspace = CBUtil.readString(body);
                            name = CBUtil.readString(body);
                            target = name.isEmpty() ? Target.KEYSPACE : Target.TABLE;
                            return new SchemaChange(change, target, keyspace, name);
                        case V3:
                            change = CBUtil.readEnumValue(Change.class, body);
                            target = CBUtil.readEnumValue(Target.class, body);
                            keyspace = CBUtil.readString(body);
                            name = (target == Target.KEYSPACE) ? "" : CBUtil.readString(body);
                            return new SchemaChange(change, target, keyspace, name);
                        default:
                            throw version.unsupported();
                    }
                }

                private Target maybeReadTarget(ChannelBuffer body, ProtocolVersion version) {
                    switch (version) {
                        case V1:
                        case V2:
                            return null;
                        case V3:
                            return CBUtil.readEnumValue(Target.class, body);
                        default:
                            throw version.unsupported();
                    }
                }
            };

            private SchemaChange(Change change, Target target, String keyspace, String name) {
                super(Kind.SCHEMA_CHANGE);
                this.change = change;
                this.target = target;
                this.keyspace = keyspace;
                this.name = name;
            }

            @Override
            public String toString() {
                return "RESULT schema change " + change + " on " + target + ' ' + keyspace + (name.isEmpty() ? "" : '.' + name);
            }
        }
    }

    public static class Event extends Message.Response {

        public static final Message.Decoder<Event> decoder = new Message.Decoder<Event>() {
            public Event decode(ChannelBuffer body, ProtocolVersion version) {
                return new Event(ProtocolEvent.deserialize(body, version));
            }
        };

        public final ProtocolEvent event;

        public Event(ProtocolEvent event) {
            super(Message.Response.Type.EVENT);
            this.event = event;
        }

        @Override
        public String toString() {
            return "EVENT " + event;
        }
    }

    public static class AuthChallenge extends Message.Response {

        public static final Message.Decoder<AuthChallenge> decoder = new Message.Decoder<AuthChallenge>() {
            public AuthChallenge decode(ChannelBuffer body, ProtocolVersion version) {
                ByteBuffer b = CBUtil.readValue(body);
                if (b == null)
                    return new AuthChallenge(null);

                byte[] token = new byte[b.remaining()];
                b.get(token);
                return new AuthChallenge(token);
            }
        };

        public final byte[] token;

        private AuthChallenge(byte[] token) {
            super(Message.Response.Type.AUTH_CHALLENGE);
            this.token = token;
        }
    }

    public static class AuthSuccess extends Message.Response {

        public static final Message.Decoder<AuthSuccess> decoder = new Message.Decoder<AuthSuccess>() {
            public AuthSuccess decode(ChannelBuffer body, ProtocolVersion version) {
                ByteBuffer b = CBUtil.readValue(body);
                if (b == null)
                    return new AuthSuccess(null);

                byte[] token = new byte[b.remaining()];
                b.get(token);
                return new AuthSuccess(token);
            }
        };

        public final byte[] token;

        private AuthSuccess(byte[] token) {
            super(Message.Response.Type.AUTH_SUCCESS);
            this.token = token;
        }
    }
}
TOP

Related Classes of com.datastax.driver.core.Responses$Event

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.