/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.cassandra.transport; import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; import java.util.List; import java.util.Optional; import org.apache.commons.lang3.ArrayUtils; /** * The native (CQL binary) protocol version. * * Some versions may be in beta, which means that the client must * specify the beta flag in the frame for the version to be considered valid. * Beta versions must have the word "beta" in their description, this is mandated * by the specs. * */ public enum ProtocolVersion implements Comparable<ProtocolVersion> { // The order is important as it defines the chronological history of versions, which is used // to determine if a feature is supported or some serdes formats V1(1, "v1", false), // no longer supported V2(2, "v2", false), // no longer supported V3(3, "v3", false), V4(4, "v4", false), V5(5, "v5-beta", true); /** The version number */ private final int num; /** A description of the version, beta versions should have the word "-beta" */ private final String descr; /** Set this to true for beta versions */ private final boolean beta; ProtocolVersion(int num, String descr, boolean beta) { this.num = num; this.descr = descr; this.beta = beta; } /** The supported versions stored as an array, these should be private and are required for fast decoding*/ private final static ProtocolVersion[] SUPPORTED_VERSIONS = new ProtocolVersion[] { V3, V4, V5 }; final static ProtocolVersion MIN_SUPPORTED_VERSION = SUPPORTED_VERSIONS[0]; final static ProtocolVersion MAX_SUPPORTED_VERSION = SUPPORTED_VERSIONS[SUPPORTED_VERSIONS.length - 1]; /** All supported versions, published as an enumset */ public final static EnumSet<ProtocolVersion> SUPPORTED = EnumSet.copyOf(Arrays.asList((ProtocolVersion[]) ArrayUtils.addAll(SUPPORTED_VERSIONS))); /** Old unsupported versions, this is OK as long as we never add newer unsupported versions */ public final static EnumSet<ProtocolVersion> UNSUPPORTED = EnumSet.complementOf(SUPPORTED); /** The preferred versions */ public final static ProtocolVersion CURRENT = V4; public final static Optional<ProtocolVersion> BETA = Optional.of(V5); public static List<String> supportedVersions() { List<String> ret = new ArrayList<>(SUPPORTED.size()); for (ProtocolVersion version : SUPPORTED) ret.add(version.toString()); return ret; } public static ProtocolVersion decode(int versionNum) { ProtocolVersion ret = versionNum >= MIN_SUPPORTED_VERSION.num && versionNum <= MAX_SUPPORTED_VERSION.num ? SUPPORTED_VERSIONS[versionNum - MIN_SUPPORTED_VERSION.num] : null; if (ret == null) { // if this is not a supported version check the old versions for (ProtocolVersion version : UNSUPPORTED) { // if it is an old version that is no longer supported this ensures that we reply // with that same version if (version.num == versionNum) throw new ProtocolException(ProtocolVersion.invalidVersionMessage(versionNum), version); } // If the version is invalid reply with the highest version that we support throw new ProtocolException(invalidVersionMessage(versionNum), MAX_SUPPORTED_VERSION); } return ret; } public boolean isBeta() { return beta; } public static String invalidVersionMessage(int version) { return String.format("Invalid or unsupported protocol version (%d); supported versions are (%s)", version, String.join(", ", ProtocolVersion.supportedVersions())); } public int asInt() { return num; } @Override public String toString() { // This format is mandated by the protocl specs for the SUPPORTED message, see OptionsMessage execute(). return String.format("%d/%s", num, descr); } public final boolean isGreaterThan(ProtocolVersion other) { return num > other.num; } public final boolean isGreaterOrEqualTo(ProtocolVersion other) { return num >= other.num; } public final boolean isSmallerThan(ProtocolVersion other) { return num < other.num; } public final boolean isSmallerOrEqualTo(ProtocolVersion other) { return num <= other.num; } }