| /* |
| * 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 envelope's header 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", false), |
| V6(6, "v6-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, V6 }; |
| final static ProtocolVersion MIN_SUPPORTED_VERSION = SUPPORTED_VERSIONS[0]; |
| final static ProtocolVersion MAX_SUPPORTED_VERSION = SUPPORTED_VERSIONS[SUPPORTED_VERSIONS.length - 1]; |
| /** These versions are sent by some clients, but are not valid Apache Cassandra versions (66, and 65 are DSE versions) */ |
| private static int[] KNOWN_INVALID_VERSIONS = {66, 65}; |
| |
| /** All supported versions, published as an enumset */ |
| public final static EnumSet<ProtocolVersion> SUPPORTED = EnumSet.copyOf(Arrays.asList(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 = V5; |
| public final static Optional<ProtocolVersion> BETA = Optional.of(V6); |
| |
| public static List<String> supportedVersions() |
| { |
| List<String> ret = new ArrayList<>(SUPPORTED.size()); |
| for (ProtocolVersion version : SUPPORTED) |
| ret.add(version.toString()); |
| return ret; |
| } |
| |
| public static List<ProtocolVersion> supportedVersionsStartingWith(ProtocolVersion smallestVersion) |
| { |
| ArrayList<ProtocolVersion> versions = new ArrayList<>(SUPPORTED_VERSIONS.length); |
| for (ProtocolVersion version : SUPPORTED_VERSIONS) |
| if (version.isGreaterOrEqualTo(smallestVersion)) |
| versions.add(version); |
| return versions; |
| } |
| |
| public static ProtocolVersion decode(int versionNum, boolean allowOlderProtocols) |
| { |
| 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 respond |
| // with that same version |
| if (version.num == versionNum) |
| throw new ProtocolException(ProtocolVersion.invalidVersionMessage(versionNum), version); |
| } |
| for (int dseVersion : KNOWN_INVALID_VERSIONS) |
| { |
| if (versionNum == dseVersion) |
| throw ProtocolException.toSilentException(new ProtocolException(ProtocolVersion.invalidVersionMessage(versionNum))); |
| } |
| |
| // If the version is invalid reply with the channel's version |
| throw new ProtocolException(invalidVersionMessage(versionNum)); |
| } |
| |
| if (!allowOlderProtocols && ret.isSmallerThan(CURRENT)) |
| throw new ProtocolException(String.format("Rejecting Protocol Version %s < %s.", ret, ProtocolVersion.CURRENT)); |
| |
| 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; |
| } |
| } |